Enumerable.Range与for循环的性能 [英] Performance of Enumerable.Range vs for loop

查看:199
本文介绍了Enumerable.Range与for循环的性能的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想知道使用Enumerable.Range的性能开销与使用foreach循环的性能开销是否相反.例如:

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. 为什么可枚举.范围更快比直接收益循环好吗?

Enumerable.Range实现

关于采用Enumerable的foreach的思考.范围与传统for循环

但是我担心最后使用Select时,实际上我可能会循环两次.但是,我喜欢使用Range选项的优雅方式.

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.

推荐答案

在以下测试中,for的效率更高:(以毫秒为单位,相差为+ -3毫秒-无关紧要.)

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

但是您可以代替使用Enumerable.Range().Select来使用.Repeat:

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

在说完上述通知后,您在这里谈论的是非常小的收藏(4件).在较大的收藏集中,尤其是如果您删除.ToArray(),其行为将有所不同:

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


但是我担心最后使用Select时,实际上我可能会循环两次

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

尽管同时使用参考源 .RangeRepeat是通过yield return实现的:

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

所以它也延迟执行,就像.Select一样,它不会循环两次.

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

并不是说Stopwatch的使用每次运行都会返回不同的结果,但是总体思路如上所述.

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

IMO ,尤其是在小型集合的情况下,由于其较小的性能改进而提高了可读性.当您已经遇到性能问题时,只有拿到更大的鱼(例如,在List<>上嵌套的for循环而不是使用HashSet<>),才可以处理类似的事情.

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.

这篇关于Enumerable.Range与for循环的性能的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆