2016-10-19 5 views
0

Enumerable.Rangeを使用した場合のパフォーマンスオーバーヘッドは、foreachループを使用していたのですか?例:Enumerable.Rangeとforループのパフォーマンス

var stringArray = Enumerable.Range(0, 4).Select(i => string.Empty).ToArray(); 

VS

  1. Why is Enumerable.Range faster than a direct yield loop?

  2. Enumerable.Range implementation

  3. Thoughts on foreach with Enumerable.Range vs traditional for loop

var stringArray = new string[4]; 
for (int i = 0; i < formatted.Length; i++) 
{ 
    stringArray[i] = string.Empty; 
} 

は、私はこれらの問題を発見しました

しかし、私は最後にSelectと恐れるので、実際には2回ループするかもしれません。しかし、私はRangeオプションを使用して優雅さが好きです。次のテストforから

+0

[高速です](https://ericlippert.com/2012/12/17/performance-rant/)を知りたいときは、自分でテストしてください。 – juharr

+0

第1の方法には、いくつかのオブジェクトのインスタンス化しかありません。 ToArrayが最大の犯人になるだろう。しかし、これはあなたが懸念しなければならないパフォーマンスの問題ではありません(通常)。これはミクロ最適化です。 –

+0

@Dennis_Eそれは他の何よりも好奇心でした。助けてくれてありがとう – jolySoft

答えて

3

は、より効率的である:(ミリ秒単位で、それは+ -3ミリ秒差 - 微々たるものである。)

var watch = System.Diagnostics.Stopwatch.StartNew(); 
var stringArra1y = Enumerable.Range(0, 4).Select(i => string.Empty).ToArray(); 
watch.Stop(); 
Console.WriteLine(watch.ElapsedTicks); //3305 

watch = System.Diagnostics.Stopwatch.StartNew(); 
var stringArray2 = new string[4]; 
for (int i = 0; i < stringArray2.Length; i++) 
{ 
    stringArray2[i] = string.Empty; 
} 
watch.Stop(); 
Console.WriteLine(watch.ElapsedTicks); //1 

しかし、あなたの代わりにEnumerable.Range().Select使用.Repeat使用することができます

var watch = System.Diagnostics.Stopwatch.StartNew(); 
var stringArra1y = Enumerable.Repeat(string.Empty, 4).ToArray(); 
watch.Stop(); 
Console.WriteLine(watch.ElapsedTicks); //391 

あなたがここでは非常に小さなコレクション(4アイテム)について話していると言った後。その後、私は、あるかもしれない

var watch = System.Diagnostics.Stopwatch.StartNew(); 
var stringArra1y = Enumerable.Repeat(string.Empty, 100000); 
watch.Stop(); 
Console.WriteLine(watch.ElapsedTicks); //360 


watch = System.Diagnostics.Stopwatch.StartNew(); 
var stringArray2 = new string[100000]; 
for (int i = 0; i < stringArray2.Length; i++) 
{ 
    stringArray2[i] = string.Empty; 
} 
watch.Stop(); 
Console.WriteLine(watch.ElapsedTicks); //1335 


しかし、私は最後に選択して恐れる:あなたは.ToArray()を削除する大規模コレクションで、特に場合は、それは同じように動作しません。 Reference Source両方.RangeRepeatを用いて実装されているものの効果、ループは二回

探しyield return

static IEnumerable<int> RangeIterator(int start, int count) { 
    for (int i = 0; i < count; i++) yield return start + i; 
} 

だから、それはあまりにもID defferedはちょうどそれが二回ループしないという意味.Selectのように、実行します。

はHESEマイナーなパフォーマンスの向上を超える読みやすくするために行かないStopwatchリターンの使用は異なる結果各実行を全体的なアイデアは、特に小さなコレクションの場合には、

IMO上に提示されていること。あなたがすでにパフォーマンスの問題に遭遇したときは、より大きな魚を手に入れた後でのみ(たとえば、HashSet<>を使用する代わりにループを入れてList<>に入れます)、このようなものを処理します。ループのために1つの000 000文字列の38msにより高速であるように見える私の非常に簡単なテストで

+0

ループははるかに速いが非常に醜い(IMHO)が、繰り返しはパフォーマンスにあまり悪くはない、まだエレガント(IMHO)です。多くは – jolySoft

+0

@jolySoft感謝 - 大規模なコレクションについての更新を参照してください:) –

+0

卓越したを、それは私が – jolySoft

1

static void Main(string[] args) 
     { 
      var start = DateTime.Now; 
      EnTest(); 
      var end = DateTime.Now; 

      var firstResult = end - start; 
      Console.WriteLine("Difference for Enumerable: {0}ms", firstResult.Milliseconds); 

      GC.Collect(); 
      Thread.Sleep(2000); 

      var secondStart = DateTime.Now; 
      ArTest(); 
      var secondEnd = DateTime.Now; 

      var secondResult = secondEnd - secondStart; 
      Console.WriteLine("Difference for loop: {0}ms", secondResult.Milliseconds); 

      var globalResult = firstResult - secondResult; 
      Console.WriteLine("Difference between tests: {0}ms", globalResult.Milliseconds); 

      Console.ReadKey(); 
     } 

     public static void EnTest() 
     { 
      var stringArray = Enumerable.Range(0, 1000000).Select(i => string.Empty).ToArray(); 
     } 

     public static void ArTest() 
     { 
      var stringArray = new string[1000000]; 
      for (int i = 0; i < stringArray.Length; i++) 
      { 
       stringArray[i] = string.Empty; 
      } 
     } 
+0

Loppを見ることができなかったループの遅延実行したRepeat'は、私は感謝し、探していたものだった '、高速だが醜いです – jolySoft

関連する問題