LoginSignup
18

More than 5 years have passed since last update.

Unity/C#における繰り返し文の速度比較

Last updated at Posted at 2015-12-19

for,while,foreachの速度差を検証してみる

[2016/02/20 追記]
全部まとめて書いてしまったので単品で書いたものとILが異なっている可能性有り
個々で検証を行うとまた結果が違うかも・・・

【検証環境】

・Unity5.2.4f1(Personal Edition)
・Nexus7(Android 5.0.2)
・100万回ループした際にかかった時間を比較

【比較項目】

①forの前置インクリメント
②for
③while
④do-while
⑤foreach
⑥forのLengthチェック
⑦forのList<T>参照
⑧forのList<T>参照のCountチェック
⑨foreachのList<T>参照
⑩whileのLinkedList<T>参照
⑪foreachのLinkedList<T>参照

【テストコード】

using UnityEngine;
using System.Collections.Generic;

public class Test : MonoBehaviour {

    void Start() {
        int count = 1000000;
        int[] array = new int[count];
        List<int> list = new List<int>(count);
        LinkedList<int> link = new LinkedList<int>();
        float prevTime, nowTime;
        int hoge;

        // 適当なデータを格納
        for (int i = 0; i < count; i++) {
            hoge = UnityEngine.Random.Range(0, 65535);
            array[i] = hoge;
            list.Add(hoge);
            link.AddLast(hoge);
        }

        // ① for前置
        prevTime = Time.realtimeSinceStartup;
        for (int i = 0; i < count; ++i) {
            hoge = array[i];
        }
        nowTime = Time.realtimeSinceStartup;
        Debug.LogError("① for前置 : " + (nowTime-prevTime));
        // ③ for後置
        prevTime = Time.realtimeSinceStartup;
        for (int i = 0; i < count; i++) {
            hoge = array[i];
        }
        nowTime = Time.realtimeSinceStartup;
        Debug.LogError("② for後置 : " + (nowTime-prevTime));
        // ③ while
        prevTime = Time.realtimeSinceStartup;
        int indexWhile = 0;
        while (indexWhile < count) {
            hoge = array[indexWhile];
            indexWhile++;
        }
        nowTime = Time.realtimeSinceStartup;
        Debug.LogError("③ while : " + (nowTime-prevTime));
        // ④ do-while
        prevTime = Time.realtimeSinceStartup;
        int indexDo = 0;
        do {
            hoge = array[indexDo];
            indexDo++;
        } while (indexDo < count);
        nowTime = Time.realtimeSinceStartup;
        Debug.LogError("④ do-while : " + (nowTime-prevTime));
        // ⑤ foreach
        prevTime = Time.realtimeSinceStartup;
        foreach (int val in array) {
            hoge = val;
        }
        nowTime = Time.realtimeSinceStartup;
        Debug.LogError("⑤ foreach : " + (nowTime-prevTime));
        // ⑥ for-length
        prevTime = Time.realtimeSinceStartup;
        for (int i = 0; i < array.Length; i++) {
            hoge = array[i];
        }
        nowTime = Time.realtimeSinceStartup;
        Debug.LogError("⑥ for-length : " + (nowTime-prevTime));
        // ⑦ for-list
        prevTime = Time.realtimeSinceStartup;
        for (int i = 0; i < count; i++) {
            hoge = list[i];
        }
        nowTime = Time.realtimeSinceStartup;
        Debug.LogError("⑦ for-list : " + (nowTime-prevTime));
        // ⑧ for-list-.Count
        prevTime = Time.realtimeSinceStartup;
        for (int i = 0; i < list.Count; i++) {
            hoge = list[i];
        }
        nowTime = Time.realtimeSinceStartup;
        Debug.LogError("⑧ for-list.Count : " + (nowTime-prevTime));
        // ⑨ foreach-list
        prevTime = Time.realtimeSinceStartup;
        foreach (int val in list) {
            hoge = val;
        }
        nowTime = Time.realtimeSinceStartup;
        Debug.LogError("⑨ foreach-list : " + (nowTime-prevTime));
        // ⑩ while-link
        prevTime = Time.realtimeSinceStartup;
        LinkedListNode<int> node = link.First;
        while (node != null) {
            hoge = node.Value;
            node = node.Next;
        }
        nowTime = Time.realtimeSinceStartup;
        Debug.LogError("⑩ while-link : " + (nowTime-prevTime));
        // ⑪ foreach-link
        prevTime = Time.realtimeSinceStartup;
        foreach (int val in link) {
            hoge = val;
        }
        nowTime = Time.realtimeSinceStartup;
        Debug.LogError("⑪ foreach-link : " + (nowTime-prevTime));
    }
}

【結果】

① for前置 : 0.01135254
② for後置 : 0.01126099
③ while : 0.01022339
④ do-while : 0.01327515
⑤ foreach : 0.01751709
⑥ for-length : 0.01556396
⑦ for-list : 0.02728271
⑧ for-list.Count : 0.03369141
⑨ foreach-list : 0.03857422
⑩ while-link : 0.01895142
⑪ foreach-link : 0.03387451

【総評】

①~④については誤差レベル
試行回数を増やして平均値とれば差もなくなりそうな感じ
Unity/C#ではインクリメントも前置が後置より必ず早いということは見受けられなかった
(そもそもILレベルで差分が出てるのだろうか・・・)
また固定配列の.Lengthは思ったよりコストが高くなかった
神経質に配列長をキャッシュする必要は必ずしもないのかもしれない

foreachは速度の問題よりイテレータのインスタンスでヒープを食うのでランタイムでは使うべきでない
Editor拡張スクリプト等で使うべきだろう

List<T>については基本的に固定配列より参照が遅い
CapacityオーバーやInsert等のコストは当然高くメモリも余剰に食うので
特にListである必要がなければ固定配列にしたい
ただSortなど色々容易なのでランタイムでも使いたくなる場面はままある

おまけのLinkedListだがwhileで始端から終端をなめる分には速度は問題ない
しかしAddの際にノードのインスタンスを作るのでヒープを食ってしまう
GCが容認しづらい環境下での重用は難しい

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
18