18
18

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

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が容認しづらい環境下での重用は難しい

18
18
0

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
18

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?