ループ中でのmy宣言と処理速度

このQ&Aのポイント
  • ループ中にmy宣言をいちいちすると処理速度は落ちてしまうのかを検証
  • ループの外で変数を宣言する方法とループの中で変数を宣言する方法がある
  • 変数をループの中で宣言する方が初期化が自動的に行われるが、メモリの解放と確保が繰り返される可能性がある
回答を見る
  • ベストアンサー

ループ中でのmy宣言と処理速度

こんにちは、Perl入門者ですがよろしくお願いします。 質問内容はループ中にmy宣言をいちいちすると処理速度は落ちてしまうのかということです。 ソースを例に挙げると まず、$lenをループの外に書く方法と my $i; my $len; for( $i=0 ; $i<1024 ; $i++){ $len = length($str[$i]; } $lenをループの中に書く方法 my $i; for($i=0 ; $i<1024 ; $i++){ my $len; $len = length($str[$i]); } の2種類です(その他の変数については特に言及していません) 使いやすさでいえば、ループ内で宣言をした方が自動的に初期化されるのでうれしいのですが ふと、いちいちメモリの解放と確保を行っているわけですからOS(?)に負荷がかかって遅くなっているのではと考えました。 Perlで処理速度を測ることもできるようですが恥ずかしいながらスキル不足です。すいません。 どなたかご存知の方、自分なりの考えがある方はご教授頂きたく存じます。 よろしくお願いします。

  • kiki28
  • お礼率71% (240/337)
  • Perl
  • 回答数1
  • ありがとう数3

質問者が選んだベストアンサー

  • ベストアンサー
  • ryu_chan
  • ベストアンサー率37% (69/186)
回答No.1

質問者さんのコードで、とりあえずベンチマークを取ってみました。 質問者さんの予想通り、変数宣言をループの外(out of loop)でしたほうが、 ループの中(in loop)でするより1.5倍近く速いという結果になりました。 Benchmark: timing 10000 iterations of in loop, out of loop... ..  in loop: 4 wallclock secs ( 3.69 usr + 0.00 sys = 3.69 CPU) @ 2711.50/s (n=10000) out of loop: 2 wallclock secs ( 2.48 usr + 0.00 sys = 2.48 CPU) @ 4025.76/s (n=10000)         Rate  in loop out of loop in loop .   2711/s.   --   -33% out of loop 4026/s.   48%    -- 私の環境は、以下です。 CPU:PentimuM 1.73MHz OS:Windows XP SP2 Perl:Active Perl 5.8.8 試したコードは以下です。 use Benchmark qw(:all); my @str = ('a'x10) x 1024; my $r = timethese( 10000, { 'out of loop' => sub { my $i; my $len; for( $i=0 ; $i<1024 ; $i++){ $len = length($str[$i]); } }, 'in loop' => sub { my $i; for($i=0 ; $i<1024 ; $i++){ my $len = length($str[$i]); } } }); cmpthese $r;

kiki28
質問者

お礼

返事が遅くなって申し訳ありません!! 回答はすぐに読ませていただきました。 非常に参考になりました。少しプログラミングの難易度は上がりますがこのあたりを気にしたプログラミングを行っていこうと思うことができました。 ありがとうございました。

関連するQ&A

  • 配列長参照のオーバーヘッド

    for等ループでループ終了条件に配列長を使用する場合、配列長を毎回参照する場合と一旦変数に格納して参照する場合、定数を使用する場合と処理速度の差はありますか? つまり 1、for( int i = 0; i < array.length; i++ ) { ... } 2、for( int i = 0; i < len; i++ ) { ... } *(int len=array.length) 3、for( int i = 0; i < 10; i++ ) { ... } *(int[] array = new int[10]) forループ内の処理のメモリ使用量の多寡は不明で、毎ループで読み取られる全ての変数はコンピュータのキャッシュに残るかどうかは不明だとします。

    • ベストアンサー
    • Java
  • ループ内での後方参照の使用に関して

    下記のようなプログラムを作成しました。 (Perl のバージョンは 5.8.8 となります。) for ($i=0; $i<=105; $i++) { $str1 = "str1"; $str2 = "1234567890str1test"; $str2=~ s/^(\d+)($str1)/test/g; print $i."\n"; print $1."\n"; print $2."\n"; print $str2."\n"; } このプログラムを実行しますと、ループが100回実施するまでは $1, $2の値を 取得できるのですが、100回を超えると取得できなくなります。 (上記で行っている置換処理は100回を超えても正常に処理されます。) 質問としましては、この現象は Perl のバグなのでしょうか。 それとも、私の正規表現の書き方に不備があるのでしょうか。 ネットでいろいろ調べてみたのですが、答えが見つからなかったため、 質問させていただきました。 よろしくお願い致します。

  • C言語で分からないところがあるのですが

    すみません。C言語のポインタで分からないことがあって来ました。 ポインタの理屈は理解してはいるのですが、いざソースコードを書いてみようということになると全く手がつけられずにいます。 以下のソースコードですが、strlen()と同じ働きをする関数mystrlen()と、strcmp()と同じ働きをする関数mystrcmpを、ポインタを使って作成するものです。どこをどうすればいいのか教えてくださいませんか。 #include <stdio.h> int main(void) { char str1[80], str2[80]; int i, j; int len1, len2; printf("第1の文字列を入力してください: "); gets(str1); printf("第2の文字列を入力してください: "); gets(str2); /* * 文字列の長さを確認する */ /* NULL文字(文字列の最後)まで読み飛ばす */ for (len1 = 0; len1 < 80 && str1[len1] != '\0'; len1++) ; /* ループ終了後、len1 に文字列の長さが入っている */ if (len1 < 80) { printf("%s は %d 文字の長さです\n", str1, len1); } else { printf ("第1の文字列が80字以上あります\n"); } /* str2 についても同様 */ for (len2 = 0; len2 < 80 && str2[len2] != '\0'; len2++) ; if (len2 < 80) { printf("%s は %d 文字の長さです\n", str2, len2); } else { printf ("第2の文字列が80字以上あります\n"); } if (len1 < 80 && len2 < 80) { for (i = 0; i < 80 && str1[i] != '\0' && str2[i] != '\0' && str1[i] == str2[i]; i++) ; if (str1[i] == str2[i]) { /* 両者同時に == '\0' のはず*/ printf("文字列は等しい\n"); } else if (str1[i] < str2[i]) { /* str1[i] == '\0' のはず*/ printf("%s は %s より小さい\n", str1, str2); } else { /* str2[i] == '\0' のはず*/ printf("%s は %s より大きい\n", str1, str2); } } /* * 十分なスペースがあれば、str2をstr1の最後に連結する */ if (len1 + len2 < 80) { /* str1 の末尾を探す */ for (i = 0; str1[i] != '\0'; i++) ; /* ループを抜けた段階では i は len1 と同じはずなので、 上記のループを作らず、i の代わりに len1 を用いるのも可 */ /* それ以降に str2 の中身をコピーする */ for (j = 0; str2[j] != '\0'; j++) { str1[i+j] = str2[j]; } str1[i+j] = '\0'; printf("%s\n", str1); } else { printf ("文字列をつなげた長さが80字以上あります\n"); } /* * str2をstr1にコピーする */ if (len1 + len2 < 80) { for (i = 0; str1[i] != '\0'; i++) { str1[i] = str2[i]; } str1[i] = '\0'; printf("%s %s\n", str1, str2); } return 0; }

  • ループで置換がうまく行きません

    こんにちは。よろしくお願いします。 以下のようなソースで、 指定した文字列があれば置換、という作業を、 配列をループさせて連続して行いたいと思っているのですが、置換されません。 ---------------- $str = "年齢は<--age-->才"; #置換したい文字列の配列 $from[0] = '<--name-->'; $to[0] = 'やまだ'; $from[1] = '<--age-->'; $to[1] = '10'; $from[2] = '<--date-->'; $to[2] = '今日'; #配列分ループして、ヒットしたら置換する for ($i=0; $i<=2; $i++){ $str=~s/$from[$i]/$to[$i]/go; } print $str; --------------------- 結果:年齢は<--age-->才 --------------------- ところが、全く同じ処理をループせずに行うとうまくいきます。 ------------------- $i = 0; $str=~s/$from[$i]/$to[$i]/go; $i = 1; $str=~s/$from[$i]/$to[$i]/go; $i = 2; $str=~s/$from[$i]/$to[$i]/go; print $str; --------------------- 結果:年齢は10才 --------------------- こんな事ってあるのでしょうか? 何か間違いがありましたら教えて下さい よろしくお願いします

    • ベストアンサー
    • Perl
  • テキストフィールドでの全角チェックについて

    テキストフィールド内にて、全角文字以外が入力されたらエラーをだすようにしています。そのとき以下のソースだと改行した時に、enterが半角とみなされてしまう現象が起こってしまいました。 function jstrlen(str) { len = 0; for (i = 0; i < str.length; i++) { wrk = escape(str.substr(i,1)); if ((wrk.substr(0,2) == "%u") && (wrk < "%uFF71")) { len++; } len++; } return len; } function isZen(str) { len1 = jstrlen(str.value); len2 = str.value.length * 2; if(len1 != len2){ alert("半角文字が混在"); str.focus() ; }else{ alert("全角文字のみ"); } } 対処方法をどなたかよろしくお願いします。

  • vb.netって変数宣言、不要ですよね?

    vb.netって変数宣言、不要ですよね? For i = 1 To 10 MsgBox(Str(i)) Next このコードで動いちゃいました。

  • Perlのmyのサブルーチンの内外での宣言の違い

    Perlでmyを使う場合、サブルーチンの内外での宣言の違いについて知りたいです。 私はよくある変数をそのプログラム内全体で使う時(カウントするだけの$iみたいなものや、DBのクエリなど)は、同じ変数名をサブルーチン内で毎回宣言するのが嫌(個人的に同じことを重複するプログラムが好きではないという主義)なので、サブルーチンの外でmyを宣言するのですが、myとかはサブルーチン外で宣言するとどんな問題が生じる可能性があるのでしょうか? また毎回サブルーチン内で宣言するのと外部で宣言するのではどういった時に問題になるのでしょうか?もちろんサブルーチンの外でmy宣言した場合はサブルーチンにその変数が引き継がれることは知っています。 リファレンス部分で変わるような記述を見たことはあります。 さしあたって問題を感じでいないのです、ふと疑問に思ったのですが、どうもそれに書かれたソースが少ないので御存知の方がいればぜひ御教授願いたいです。 <例> my $hoge; sub hoge1 { $hoge = 1; } sub hoge2 { $hoge = 5; } と sub hoge1 { my $hoge = 1; } sub hoge2 { my $hoge = 5; }

    • ベストアンサー
    • Perl
  • setTimeoutをループさせDOMを処理したい

    「setTimeout」「for文」「jQuery」を利用して、1秒ごとに、 <div class="hoge1">、<div class="hoge2">、<div class="hoge3">へ対して、同じ処理をしたいです ■処理内容イメージ ・ループカウントの変数iを渡して、それぞれのdiv内で、1、2、3と表示 ■質問 「setTimeout」を1秒ごとに、指定DOMへ対して、ループさせる方法を教えてください ※ループできるなら、「for文」じゃなくても良いです

  • ループの終わらせ方

    あるboolean配列でtrueなら■falseなら□を表示させ、時間とともにある規則で動かしていくプログラムを組みました。配列の宣言などを省略してますがこんな感じです。 do{ boolean[] box2 = (boolean[]) box.clone(); for ( i = 0; i < box2.length; i++) { if (box2[i]) { // コピーの玉があったら // 右方向に向かって空き箱を探す。 for (int j = 1; j < box.length; j++) { int p = (i + j) % box.length; if (! box[p]) { // 空き箱を見つけたので玉を入れる(trueにする)  box[p] = true; // 元の場所は玉を消す(falseにする) box[i] = false; // box2[i]はもう二度と調べないのでそのまま放置 break;   } }   } } box2 = null; for(h=0; h < box.length; h++){   if(box[h] == false) System.out.print("□"); if(box[h] == true) System.out.print("■"); } r++; }while(box == box && r<20); ちなみに表示結果は □■■□□■□□■□□■ ■□□■■□■□□■□□ □■□□□■□■■□■□ ・ ・ こんな感じになります。ここで質問なんですが、 過去と同じ配置の配列が出てきた時点でwhile文の ループを終わらせるにはどうすればよいでしょうか? 現時点ではループが20回になった時点で止めるようにしてます。

  • ループ処理について

    下記のようなScriptを記述しました。 for(i = 1; i <= 4 ; i++) { trace("A") ; var fileload:LoadVars = new LoadVars(); fileload.load("b"+i+".jpg"); fileload.onLoad = function(success:Boolean) { trace("B") ; if (!success) { ok_flg = 1; } else { a.duplicateMovieClip("b"+i, i); this["b"+i].loadMovie("b"+i+".jpg") ; this["b"+i]._x += (i - 1) * 90 ; } }; } 本来ならJPEGが存在する分だけ読込むと言う処理をしたいのですが、テスト的に3ファイル用意してテストしました。 JPEGの命名規則は「b1~b3」としています。 普通のループ文であれば問題無く3件のJPEGが表示されますが、読み込みが成功したか否かの判断文を入れると動作がおかしくなります。 TRACEを入れてみたら、 A A A A B Error opening URL "file:///C|/Documents%20and%20Settings/xxxxx/デスクトップ/b4.jpg" B B B このように最初に読み込みの処理を実行し、その後に成功したか否かの判定が処理されます。 これって、正常なループの処理でしょうか?。 また、私が処理したかったようにするにはどのようなScriptにすれば良いのでしょうか?。 宜しくご教授ください。

    • ベストアンサー
    • Flash

専門家に質問してみよう