[戻る] 最新記事| 前後の記事|

- 以下は、記事NO. 13588 に関する 返信フォーム です -
1フレーム内の処理限界によるオブジェクトの動作のスキップ 投稿者 : ぐりーんげーむ。(p14139-ipngn2101hodogaya.kanagawa.ocn.ne.jp)
- 2012/09/08(Sat) 01:12 No.13587
 


質問では無いのですが、過去ログに情報が見当たらず
この仕様のせいで一時間近く潰されたので書き込みます。
Tonyuのバージョンは1.26です。

まず新しいプロジェクトで下記のオブジェクトを作って実行してください。

//オブジェクトその1
extends SpriteChar;
while(1) {
  print("☆");
  update();
}

//オブジェクトその2
extends SpriteChar;
while(1) {
  j=1;
  for (i=0;i<9999999;i++) {j++;}
  print("★");
  update();
}

コンソールには☆★☆★...と表示される、と思っていたのですが
いざ実行すると☆☆☆☆...となってしまいます。
どうやら、その2はfor文の途中で処理を飛ばされているようです。
これが並列処理……!!
1フレーム1オブジェクトに処理を集中させるのは止めたほうが良さそうです。

特にロードで大量のファイルを読み込むときは
読み込む前に他のオブジェクトが動き出して、予想だにしないバグができたりします。
updateとは何だったのか……
直列処理に慣れてる人は特に忘れやすい仕様だと思うので気をつけましょ〜(^o^


Re: 1フレーム内の処理限界によるオブジェクトの動作のスキップ 投稿者 : マッキー(p3063-ipbf1910sapodori.hokkaido.ocn.ne.jp)
- 2012/09/08(Sat) 05:39 No.13588
 
この仕様って厄介な時ありますよねー!

ちょっと補足しに来ました!
一応無理やりな方法ではありますが、1つのオブジェクトに処理を集中させても処理が飛ばされないようにすることができます。

ただ、この処理はめんどくさいところがあるので、
普通にやるなら、大量のファイルを読み込むときは、読み込みオブジェクトが読み終わるまで、
他のオブジェクトが待つような方法を使った方が、やりやすいと思います。
・timeStop()で他のオブジェクトを止めて、読み終わったらreleaseAll()で再開させる
・読み込み完了のフラグをたてる変数を作り、読み込み中は0、読み終わったら1にして、他のオブジェクトはその変数が1になるまで待つ
など

無理やりな方法とは、execメソッドを使った方法のことで、スーパープロセッサのReadMeでも紹介しました。
ttp://hoge1e3.sakura.ne.jp/tonyu/project/pages/viewProject.cgi?mainkey=277&

exec()はそのオブジェクトを実行させるメソッドです。
オブジェクト生成時にappearを使えば、Tonyuが自動的にオブジェクトを実行しますが、それは自動的にexec()を呼び出しているからです。
newだけでオブジェクトを生成すれば、そのオブジェクトは動作しませんが、exec()を使うと手動でオブジェクトを実行します。

ぐりーんげーむ。さんの例をexec()の方法でやるなら、下記のようになります。

//オブジェクトその1 (MainChar.tonyu)
extends SpriteChar;
while(1) {
  print("☆");
  update();
}

//オブジェクトその2 (MainChar2.tonyu)
extends SpriteChar;
if (mode == null) { // メインの処理
  
  obj = new MainChar2(); // オブジェクトを生成
  obj.mode = 1; // exec()で実行されるオブジェクトになる
  proc = new classes.lang.Process(obj, "", 1); // Processオブジェクトを生成
  
  while(1) {
    $MainChar2_j = 1; // カウントリセット
    for (i=0; i<2000; i++) {
      proc.exec(); // 2000回ずつ実行
    }
    print("★");
    update();
  }
  
} else if (mode == 1) { // 分散させる処理
  
  while (1) {
    for (i=0; i<5000; i++) {
      $MainChar2_j ++; // 5000回繰り返す
    }
    update();
  }
  
}

オブジェクトは、MainCharが1つ、MainChar2が2つ作られます。
MainChar2は自分自身をもう1つ作り2つになりますが、1つはオブジェクトを繰り返し実行させ、
もう1つはexec()で呼び出されたとき処理を実行します。
exec()はProcessオブジェクトから出ないと呼び出せないので、
ProcessにMainChar2を関連付けて、Processを生成してから、
exec()を呼び出します。

5000回プラス1するオブジェクトを2000回実行しているので、
10000000回プラス1したことになります。
(回数はバランス良く割り振らないと処理が途中で飛ばされてしまいます)
ただ、処理を途中で飛ばすことがなくなるので、
処理が返ってくるのに時間がかかり、Tonyuウィンドウに応答なしと出ることがあります。

反応が鈍くなるのを避けたいなら、普通の方法で…
どうしても処理が飛ばされないようにしたいなら、exec()の方法
というように使い分けるといいとでしょう!


Re: 1フレーム内の処理限界によるオブジェクトの動作のスキップ 投稿者 : リセッタ(ai126213005219.5.tss.access-internet.ne.jp)
- 2012/09/09(Sun) 02:20 No.13589
 
ふむふむ、なるほど。
なかなか興味深い話題ですね。
スーパープロセッサのReadMe を きちんと読めば、
表示結果は、”☆☆☆☆……☆★☆……☆☆☆……”になると。

# 処理を飛ばすを、以降キャンセルしちゃうと解釈しちゃう人もいるかもと

#  スーパープロセッサのReadMeで 少し気になった点
#「オブジェクトの処理量を増やす方法2」
#  while (1) {
#    proc.exec(); // 実行
#    proc.aobj.draw();  // 描画
#    update();
#  }
#  は、
#  function onDraw() {
#    proc.aobj.draw();  // 描画
#  }
#  じゃ、だめなの?


Re: 1フレーム内の処理限界によるオブジェクトの動作のスキップ 投稿者 : マッキー(p4117-ipbf805sapodori.hokkaido.ocn.ne.jp)
- 2012/09/10(Mon) 01:23 No.13590
 
>表示結果は、”☆☆☆☆……☆★☆……☆☆☆……”になると。
No.13588 のプログラムは、MainCharとMainChar2のオブジェクトを1つずつ作成して実行すれば
処理が重いながらも、"☆★☆★☆★…" と表示されます。

>処理を飛ばすを、以降キャンセルしちゃうと解釈しちゃう人もいるかもと
そうですね。ReadMeに書いてるように「オブジェクトの処理が後回しにされる」といった方が誤解されないかもしれません。(自分で書いておきながら忘れてた…)

function onDraw() {} で proc.aobj.draw(); を呼び出しても問題なく動きます。
ただ、onDraw()は注意が必要でこのメソッドは設計中にも呼び出されます。
設計中は、procにオブジェクトが入っていない状態で proc.aobj.draw(); が呼び出されるのでエラーが発生してしまいます。
onDraw() で呼び出すときは設計中に真を返す designMode() を使って、実行時にだけ proc.aobj.draw(); を呼び出した方がいいです。

ちなみに、onDraw() でprocにオブジェクトを生成して代入することもできますが、onDraw() は update() の後に呼ばれるので、今度は proc.exec(); でエラーになります。
if (proc) proc.exec(); と書けばエラーは無くなりますが可読性が悪くなるので、onDraw() 内ではオブジェクトを作らない方がいいです。

以下 onDraw() を使った場合の「オブジェクトの処理量を増やす方法2」のプログラム

/* MainChar.tonyu */
extends SpriteChar;

// オブジェクトとプロセスを生成
proc = new classes.lang.Process(new SubChar(100, 100, 7), "", 1);

function onDraw() {
  if (!designMode()) proc.aobj.draw(); // 描画
}

while (1) {
  proc.exec(); // 実行
  update();
}

/* SubChar.tonyu */
extends SpriteChar;

while (1) {
  x++;
  update();
}


処理を後回しにする仕様は厄介なこともありますが、プログラムミス(無限ループとか)したときに Tonyu が固まりにくい(応答なしになりにくい)という長所?もあるんですよねー
(Tonyu自体昔に作られたので、Windows 98 とかの低スペックPCでも固まらないようにそういう仕様が作られたのかも…)
実際、exec()で処理が後回しにされないようにすると、反って重くなってしまうことがあります。それに、ソースの可読性が悪くなります。
まあ、こだわりを持った中級者・上級者向けの方法だと思ってください(^^;


1フレーム内の処理限界によるオブジェクトの動作のスキップ 投稿者 : リセッタ(ai126213147065.5.tss.access-internet.ne.jp)
- 2012/09/10(Mon) 14:15 No.13591
 
返信ありがとうございます。
描画は、描画タイミングでやりたかったもので。

キッチリ作るとすると こうかな?

function onDraw() {
// super.onDraw();  // “onDraw()”メソッドが定義済のクラスを継承している場合のみコメントを外す……やりすぎ?
  // デザインモードではなく、かつ、“proc”が定義済なら 描画
  if (!designMode() && proc) proc.aobj.draw();
}


Re: 1フレーム内の処理限界によるオブジェクトの動作のスキップ 投稿者 : マッキー(p1070-ipbf908sapodori.hokkaido.ocn.ne.jp)
- 2012/09/11(Tue) 21:57 No.13592
 
>  if (!designMode() && proc) proc.aobj.draw();
なるほど! この条件式の方がエラーになりにくくより安全ですね。

そういえば言い忘れてたことがありました…
ReadMeにも書くの忘れていましたが、appearを使わないで生成したオブジェクトは、
die() を使っても消えてくれません。あと、wait() も無視されます。

生成時にappearを使った時は、Tonyu内部で die(), wait() を呼び出したときの管理を自動的に行ってくれるのですが、
appearを使わないと自動管理の対象外になります。

appearを使わないときは、wait() は updateEx() で代用し、
die() は _pProc.kill(); と呼び出して代用できます。
_pProc はPlainCharクラス(SpriteChar,DxChar,TextChar,PanelChar,SecretChar 等の親クラス)の隠し変数で、自分を動かしてくれるProcessオブジェクトを指しています。

[オブジェクトの待機・削除ができるように]
/* MainChar.tonyu */
extends SpriteChar;

// オブジェクトとプロセスを生成
proc = new classes.lang.Process(new SubChar(100, 100, 7), "", 1);

function onDraw() {
 //super.onDraw();  // “onDraw()”メソッドが定義済のクラスを継承している場合のみコメントを外す……やりすぎ?
  // デザインモードではなく、かつ、“proc”が定義済なら 描画
  // 追加:proc.aobjが死ぬと変数の値が0になりエラーになるので proc.aobjも判断
  if (!designMode() && proc && proc.aobj) proc.aobj.draw();
}

while (1) {
  
  if (proc) proc.exec(); // 実行
  if (getkey(88)) wait(60); // Xキー:1秒待つ
  if (getkey(86)) die();    // Vキー:消す
  update();
}

/* SubChar.tonyu */
extends SpriteChar;

function onDie() {
  _pProc.kill(); // kill()だけだとオブジェクト変数がゼロクリアされないので、一応die()を呼び出すようにする
}

while (1) {
  x++;
  if (getkey(90)) updateEx(60); // Zキー:1秒待つ
  if (getkey(67)) die();        // Cキー:消す
  update();
}


ちなみに、他のオブジェクトのオブジェクト変数やグローバル変数に、消したいオブジェクトが参照されていると、そのオブジェクトは完全には消えません。
://hoge1e3.sakura.ne.jp/tonyu/wiki/index.php?%A5%AC%A5%D9%A1%BC%A5%B8%A5%B3%A5%EC%A5%AF%A5%BF

「ツール」→「オブジェクト一覧」ウィンドウを見ると、オブジェクトが残っているかどうか見れます。
設計中の画面で作られたオブジェクトは「$MyChar, $MyChar_1, $MyChar_2, …」のようにグローバル変数ができてしまうため、
die() を呼び出しても、グローバル変数がオブジェクトを参照しているため、一覧に残りっぱなしになります・・・

ページ切替しても、一覧に残りっぱなしでどんどんたまっていきますし…
何回もページ切替すると一覧から消えることもありますが、その割にはメモリ使用量減らないし…

kill() 使ってたらもしかしてメモリリークを防げるんじゃないかと思い、またスーパープロセッサのように Kernel を改造してたので、返信遅れました… (^^;;
結局、知らない変数からもオブジェクトが参照されているようで、設計中の画面で作られたオブジェクトは完全には消えてくれませんでした…
(やっぱり、メモリリークからは逃れられない・・・(--;) )


おなまえ
Eメール
タイトル
メッセージ
推薦記事
添付File
削除キー (自分の記事を削除時に使用。英数字で8文字以内)
文字色