Performance of Enumerable.Range vs for loop

流过昼夜 提交于 2020-03-18 07:00:31

问题


I wondered what the performance overhead is of using Enumerable.Range was against using a foreach loop. For example:

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

VS.

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

I spotted these question:

  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

But I fear with the Select at the end then I might be, in effect, loop twice. However I like the elegance of using the Range option.


回答1:


From the following test the for is more efficient: (in milliseconds it is +-3 ms difference - which is insignificant..)

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

But you can instead of using Enumerable.Range().Select use .Repeat:

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

After saying the above notice that you are talking here about very small collections (4 items). In larger collections, and especially if you remove the .ToArray() it doesn't behave the same:

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


But I fear with the Select at the end then I might be, in effect, loop twice

Looking though the Reference Source both the .Range and Repeat are implemented with a yield return:

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

So it too id deffered executed, just like the .Select meaning it does not loop twice.

Not that the use of the Stopwatch returns different results each run but the overall idea is as presented above

IMO, especially in the case of small collections go for readability over hese minor performance improvements. When you already hit performance issues, only after getting the bigger fish (for instance nested for loops on List<> instead of using a HashSet<>), deal with stuff like this.




回答2:


In my very simple test it looks like for loop is faster by 38ms for 1 000 000 strings.

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;
            }
        }


来源:https://stackoverflow.com/questions/40129813/performance-of-enumerable-range-vs-for-loop

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!