Enumerable.Range 与 for 循环的性能
Performance of Enumerable.Range vs for loop
我想知道使用 Enumerable.Range
相对于使用 foreach
循环的性能开销是多少。例如:
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;
}
我发现了这些问题:
Why is Enumerable.Range faster than a direct yield loop?
Enumerable.Range implementation
Thoughts on foreach with Enumerable.Range vs traditional for loop
但我担心最后的 Select
实际上可能会循环两次。但是我喜欢使用 Range
选项的优雅。
从以下测试中,for
效率更高:(以毫秒为单位,相差 +-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 项)。在较大的集合中,尤其是如果您删除 .ToArray()
,它的行为就不一样了:
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
尽管 Reference Source .Range
和 Repeat
都是通过 yield return
实现的:
static IEnumerable<int> RangeIterator(int start, int count) {
for (int i = 0; i < count; i++) yield return start + i;
}
所以它也被延迟执行,就像.Select
意味着它不会循环两次。
并不是说使用了Stopwatch
returns每个结果都不一样运行但是总体思路就是上面介绍的
IMO,尤其是在小集合的情况下,通过这些微小的性能改进来提高可读性。当你已经遇到性能问题时,只有在得到更大的鱼之后(例如 List<>
上的嵌套 for
循环而不是使用 HashSet<>
),处理这样的事情。
在我非常简单的测试中,对于 1 000 000 个字符串,for 循环似乎快了 38 毫秒。
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;
}
}
我想知道使用 Enumerable.Range
相对于使用 foreach
循环的性能开销是多少。例如:
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;
}
我发现了这些问题:
Why is Enumerable.Range faster than a direct yield loop?
Enumerable.Range implementation
Thoughts on foreach with Enumerable.Range vs traditional for loop
但我担心最后的 Select
实际上可能会循环两次。但是我喜欢使用 Range
选项的优雅。
从以下测试中,for
效率更高:(以毫秒为单位,相差 +-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 项)。在较大的集合中,尤其是如果您删除 .ToArray()
,它的行为就不一样了:
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
尽管 Reference Source .Range
和 Repeat
都是通过 yield return
实现的:
static IEnumerable<int> RangeIterator(int start, int count) {
for (int i = 0; i < count; i++) yield return start + i;
}
所以它也被延迟执行,就像.Select
意味着它不会循环两次。
并不是说使用了Stopwatch
returns每个结果都不一样运行但是总体思路就是上面介绍的
IMO,尤其是在小集合的情况下,通过这些微小的性能改进来提高可读性。当你已经遇到性能问题时,只有在得到更大的鱼之后(例如 List<>
上的嵌套 for
循环而不是使用 HashSet<>
),处理这样的事情。
在我非常简单的测试中,对于 1 000 000 个字符串,for 循环似乎快了 38 毫秒。
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;
}
}