Enumerable.Range与for循环的性能 [英] Performance of Enumerable.Range vs for loop
问题描述
我想知道使用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:
关于采用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
尽管同时使用参考源 .Range
和Repeat
是通过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屋!