セキセイインコの女の子 [セキセイインコ]
我が家のセキセイインコの " イコ " ちゃんは、2年前、2014年3月生まれで同年7月21日に迎え入れた2歳の女の子です。
生後約4ヶ月でお迎えして1ヶ月少々が経過した頃に手乗りになってくれました。
初めは男の子かと思っていたのですが、同年の冬になってからイコちゃんの鼻の蝋膜の色が茶色になった為、女の子である事が判明致しました。
セキセイインコの男の子は人の言葉を良く喋る反面、女の子は余り喋らないそうですが、イコちゃんは人の姿が見えない時に限って、 " イコちゃん! " と自分の名前を言います。
特に午前中、天気が良い日は彼女は何度も自分の名前を喋ります。
そして、稀にですが、 " イコちゃん、こんにちは! " と喋ることがあります。
https://c1.staticflickr.com/1/259/31748164046_7743e240b9_o.png
https://c1.staticflickr.com/1/283/31748162346_caa9339a33_o.png
https://c1.staticflickr.com/1/625/31748160596_9b3f092950_o.png
イコちゃんは放鳥時に人間だけで会話をしていると、嫉妬して少し怒ったりします。
生後約4ヶ月でお迎えして1ヶ月少々が経過した頃に手乗りになってくれました。
初めは男の子かと思っていたのですが、同年の冬になってからイコちゃんの鼻の蝋膜の色が茶色になった為、女の子である事が判明致しました。
セキセイインコの男の子は人の言葉を良く喋る反面、女の子は余り喋らないそうですが、イコちゃんは人の姿が見えない時に限って、 " イコちゃん! " と自分の名前を言います。
特に午前中、天気が良い日は彼女は何度も自分の名前を喋ります。
そして、稀にですが、 " イコちゃん、こんにちは! " と喋ることがあります。
https://c1.staticflickr.com/1/259/31748164046_7743e240b9_o.png
https://c1.staticflickr.com/1/283/31748162346_caa9339a33_o.png
https://c1.staticflickr.com/1/625/31748160596_9b3f092950_o.png
イコちゃんは放鳥時に人間だけで会話をしていると、嫉妬して少し怒ったりします。
JavaScriptでのループ処理速度を計測して比較してみました。 [プログラミング]
私は自作のHTML5 ディジタル インタラクティヴ アート プログラムのコードを書いている中で、処理速度を向上させる為に試行錯誤しております。
例えば、複数の種類の図形を大量に同時に動かすアニメーションの処理を軽量化する為に次の様な方法を用いております。
まず、レイヤーとして使用する為に、小さなCanvas Contextを図形の種類の数だけ配列に格納して準備致します。
図形を予めそれらのレイヤーに種類毎に1つずつ描画しておきます。
図形が描かれたレイヤーを、インターヴァル タイマーなどで定期的に呼び出した関数内で位置と縮尺を変えながら画面表示用のCanvasに大量に転写させます。
この方法は前述のプログラムの中では、煌めく粒子が大量に放出されて別々の方向へ飛んで行くアニメーションの為に使用しております。
粒子が放出される度に、粒子の画像に色が異なる円形のグラデーションを適用しており、個々の粒子毎に大きさも飛んで行く方向も異なるので、それら個々の粒子毎に描画し直していては処理が追いつかないのです。
また、物理計算などに於いては同様の処理を大量に繰り返す、ループ処理が多用されます。
ループ処理の繰り返し回数が膨大であると、プログラムの処理待ち時間が長くなり、ユーザーは苛々してしまいます。
私はギターの弦の振動をシミュレートして音を出す機能を前述のプログラムに組み込んでありますが、この計算の中では長い時間が掛かる繰り返しの計算処理を回数に制限を掛けて分割し、制限の回数に達した時点で、 " setTimeout(); " 関数で待ち時間を " 0 " [ms]として計算処理を行う関数を再び呼び出して続きの処理を行うという流れを繰り返し、既定の処理が全て完了した時点で、同様にしてその後の処理を行う関数を呼び出すようにしております。
この様にすることで、 " setTimeout(); " 関数が呼ばれた瞬間に処理が一旦解放され、処理待ちのキューに溜まっていた別の処理を実行する事が可能となり、プログラム全体の動きが止まってしまう事を避けることが出来ます。
ここからが本題ですが、ループ処理そのものの速度を上げるにはどうしたら良いでしょうか。
ウェブ上には様々な情報がございますが、環境やウェブ ブラウザーのヴァージョンなどにより結果は異なるようです。
私は2016年12月17日現在の私の環境での複数種類のループ処理の速度を実測してみることに致しました。
尚、私の環境は次の通りです。
・CPU: Intel Core i7-3770T ( 22[nm], TDP 45[W], Base Clock Frequency 2.50[GHz], Turbo Boost Clock Frequency 3.70[GHz], 4 Cores, 8 Threads )
・Main memory: CFD ELIXIR W3U1600HQ-8G ( DDR3 SDRAM PC3-12800 8GB*4 )
・Video Card: Palit GeForce GTX 750 KalmX (Fanless)
・OS: Ubuntu 16.04 LTS
・Linux kernel: 4.4.0
・Web browser: Firefox 50.1.0
まず、計測する際に使用したコードの例を掲載致します。
形式としては、まず比較対象の2種類のループ処理を一括で逐次実行する形とし、それらを纏めてループ処理で4回計測してそれぞれのループ処理の合計の処理時間を計測するものと致しました。
尚、実行順による処理時間の差が出ますので、2回目は順序を入れ替えて計測致しました。
この記事の中では上記コード内の2つのfor文を便宜的に、 " インクリメント評価方式 " 、 " デクリメント評価方式 " と呼ばせて頂きます。
私の環境では、有意な速度差が計測出来ました。
ループ回数が " 符号付き32 bit整数型 " の最大値である " 2147483647 " (2^31)以下の場合は、上のコードにある、 " インクリメント評価方式 " の方が " デクリメント評価方式 " よりも高速でした。
・インクリメント評価方式: 14680[ms](1回目の合計値), 15778[ms](2回目の合計値)
・デクリメント評価方式: 17808[ms](1回目の合計値), 17280[ms](2回目の合計値)
逆に、ループ回数が " 符号付き64 bit整数型 " の範囲となる " 2147483648 " (2^31 + 1)以上の場合は、上のコードにある、 " デクリメント評価方式 " の方が " インクリメント評価方式 " よりも高速でした。
・インクリメント評価方式: 23440[ms](1回目の合計値), 23450[ms](2回目の合計値)
・デクリメント評価方式: 21488[ms](1回目の合計値), 21345[ms](2回目の合計値)
推測ですが、 " デクリメント評価方式 " ではループ回数が " 符号付き32 bit整数型 " の範囲内では、条件式の中の2つの数値の比較の処理コストは大きくなく、一方で、計数の為のデクリメントされて行く変数と、ループ内の処理で使用する為のインクリメントされて行く変数の2つの変数を使用していることによる処理のコストが大きくなるのかもしれません。
一方、ループ回数が " 符号付き64 bit整数型 " の範囲となると、大きなデータ型同士の比較を毎回繰り返さなくてはならない " インクリメント評価方式 " に比べて、 " デクリメント評価方式 " では条件式の評価の仕方が " 0か非0か " だけなので、処理コストが小さくなったのかもしれません。
尚、 " デクリメント評価方式 " で私が何故カウント ダウン用の変数と、インクリメント用の変数の2つの変数を用いているのかと申しますと、ループ処理内で頻繁に利用される配列を用いた処理をする際、配列に後ろから前に向かって値を入れて行くと桁違いに処理が遅くなってしまうので、配列の要素番号は昇順で使用すべきだからです。
一方、別の計測で、 " for文 " と " while文 " の実行速度を比較致しましたが、その速度差は誤差程度しかございませんでした。
また、前置インクリメントと後置インクリメントにも速度差は誤差程度しかございませんでした。
結論と致しましては、 " 2147483648 " 回にも達するような繰り返し計算をするならば途中で処理を分割するべきですので、通常の繰り返し回数内で明らかに高速である、上記コード内の " インクリメント評価方式 " を使用したいと思います。
また、ループ処理の中で使用する変数は1つでも少ない方が高速な処理が可能です。
ところで、この結果はあくまで私の計測した環境上でのものですので、環境が異なれば結果は違ったものとなります。
また、私の理解が間違っている可能性もございますが、御容赦下さいませ。
例えば、複数の種類の図形を大量に同時に動かすアニメーションの処理を軽量化する為に次の様な方法を用いております。
まず、レイヤーとして使用する為に、小さなCanvas Contextを図形の種類の数だけ配列に格納して準備致します。
図形を予めそれらのレイヤーに種類毎に1つずつ描画しておきます。
図形が描かれたレイヤーを、インターヴァル タイマーなどで定期的に呼び出した関数内で位置と縮尺を変えながら画面表示用のCanvasに大量に転写させます。
この方法は前述のプログラムの中では、煌めく粒子が大量に放出されて別々の方向へ飛んで行くアニメーションの為に使用しております。
粒子が放出される度に、粒子の画像に色が異なる円形のグラデーションを適用しており、個々の粒子毎に大きさも飛んで行く方向も異なるので、それら個々の粒子毎に描画し直していては処理が追いつかないのです。
また、物理計算などに於いては同様の処理を大量に繰り返す、ループ処理が多用されます。
ループ処理の繰り返し回数が膨大であると、プログラムの処理待ち時間が長くなり、ユーザーは苛々してしまいます。
私はギターの弦の振動をシミュレートして音を出す機能を前述のプログラムに組み込んでありますが、この計算の中では長い時間が掛かる繰り返しの計算処理を回数に制限を掛けて分割し、制限の回数に達した時点で、 " setTimeout(); " 関数で待ち時間を " 0 " [ms]として計算処理を行う関数を再び呼び出して続きの処理を行うという流れを繰り返し、既定の処理が全て完了した時点で、同様にしてその後の処理を行う関数を呼び出すようにしております。
この様にすることで、 " setTimeout(); " 関数が呼ばれた瞬間に処理が一旦解放され、処理待ちのキューに溜まっていた別の処理を実行する事が可能となり、プログラム全体の動きが止まってしまう事を避けることが出来ます。
ここからが本題ですが、ループ処理そのものの速度を上げるにはどうしたら良いでしょうか。
ウェブ上には様々な情報がございますが、環境やウェブ ブラウザーのヴァージョンなどにより結果は異なるようです。
私は2016年12月17日現在の私の環境での複数種類のループ処理の速度を実測してみることに致しました。
尚、私の環境は次の通りです。
・CPU: Intel Core i7-3770T ( 22[nm], TDP 45[W], Base Clock Frequency 2.50[GHz], Turbo Boost Clock Frequency 3.70[GHz], 4 Cores, 8 Threads )
・Main memory: CFD ELIXIR W3U1600HQ-8G ( DDR3 SDRAM PC3-12800 8GB*4 )
・Video Card: Palit GeForce GTX 750 KalmX (Fanless)
・OS: Ubuntu 16.04 LTS
・Linux kernel: 4.4.0
・Web browser: Firefox 50.1.0
まず、計測する際に使用したコードの例を掲載致します。
|
形式としては、まず比較対象の2種類のループ処理を一括で逐次実行する形とし、それらを纏めてループ処理で4回計測してそれぞれのループ処理の合計の処理時間を計測するものと致しました。
尚、実行順による処理時間の差が出ますので、2回目は順序を入れ替えて計測致しました。
この記事の中では上記コード内の2つのfor文を便宜的に、 " インクリメント評価方式 " 、 " デクリメント評価方式 " と呼ばせて頂きます。
私の環境では、有意な速度差が計測出来ました。
ループ回数が " 符号付き32 bit整数型 " の最大値である " 2147483647 " (2^31)以下の場合は、上のコードにある、 " インクリメント評価方式 " の方が " デクリメント評価方式 " よりも高速でした。
・インクリメント評価方式: 14680[ms](1回目の合計値), 15778[ms](2回目の合計値)
・デクリメント評価方式: 17808[ms](1回目の合計値), 17280[ms](2回目の合計値)
逆に、ループ回数が " 符号付き64 bit整数型 " の範囲となる " 2147483648 " (2^31 + 1)以上の場合は、上のコードにある、 " デクリメント評価方式 " の方が " インクリメント評価方式 " よりも高速でした。
・インクリメント評価方式: 23440[ms](1回目の合計値), 23450[ms](2回目の合計値)
・デクリメント評価方式: 21488[ms](1回目の合計値), 21345[ms](2回目の合計値)
推測ですが、 " デクリメント評価方式 " ではループ回数が " 符号付き32 bit整数型 " の範囲内では、条件式の中の2つの数値の比較の処理コストは大きくなく、一方で、計数の為のデクリメントされて行く変数と、ループ内の処理で使用する為のインクリメントされて行く変数の2つの変数を使用していることによる処理のコストが大きくなるのかもしれません。
一方、ループ回数が " 符号付き64 bit整数型 " の範囲となると、大きなデータ型同士の比較を毎回繰り返さなくてはならない " インクリメント評価方式 " に比べて、 " デクリメント評価方式 " では条件式の評価の仕方が " 0か非0か " だけなので、処理コストが小さくなったのかもしれません。
尚、 " デクリメント評価方式 " で私が何故カウント ダウン用の変数と、インクリメント用の変数の2つの変数を用いているのかと申しますと、ループ処理内で頻繁に利用される配列を用いた処理をする際、配列に後ろから前に向かって値を入れて行くと桁違いに処理が遅くなってしまうので、配列の要素番号は昇順で使用すべきだからです。
一方、別の計測で、 " for文 " と " while文 " の実行速度を比較致しましたが、その速度差は誤差程度しかございませんでした。
また、前置インクリメントと後置インクリメントにも速度差は誤差程度しかございませんでした。
結論と致しましては、 " 2147483648 " 回にも達するような繰り返し計算をするならば途中で処理を分割するべきですので、通常の繰り返し回数内で明らかに高速である、上記コード内の " インクリメント評価方式 " を使用したいと思います。
また、ループ処理の中で使用する変数は1つでも少ない方が高速な処理が可能です。
ところで、この結果はあくまで私の計測した環境上でのものですので、環境が異なれば結果は違ったものとなります。
また、私の理解が間違っている可能性もございますが、御容赦下さいませ。