【发布时间】:2018-07-19 08:08:12
【问题描述】:
我尝试使用 Linq 和非 Linq 方法做同样的事情,发现 Linq 速度明显较慢 (~3000x)。
这是为什么呢?
Linq方式:
for (int i = 0; i < totalElements; i += stepSize)
{
var currentBlock = testList
.Skip(i)
.Take(stepSize);
result.Add(currentBlock.Sum());
}
result.ToList();
非Linq方式:
for (int i = 0; i < totalElements; i += stepSize)
{
var currentBlock = testList.GetRange(i, stepSize);
result2.Add(currentBlock.Sum());
}
result2.ToList();
结果:
方法:Linq,耗时:26667 ms,元素:1000000,步长:100
方法:GetRange,耗时:9 毫秒,元素:1000000,步长:100
根据要求提供完整的源代码:
static void Main(string[] args)
{
var totalElements = 1000000;
var testList = new List<int>(totalElements);
var rand = new Random();
// Initialize the list to random integers between 1 and 1000
for (int i = 0; i < totalElements; i++)
{
testList.Add(rand.Next(1, 1000));
}
var result = new List<int>();
var stepSize = 100;
var stp = new Stopwatch();
stp.Start();
for (int i = 0; i < totalElements; i += stepSize)
{
var currentBlock = testList
.Skip(i)
.Take(stepSize);
result.Add(currentBlock.Sum());
}
result.ToList();
stp.Stop();
Console.WriteLine($"Method: Linq, Time taken: {stp.ElapsedMilliseconds} ms, Elements: {totalElements}, Step Size: {stepSize}");
stp.Reset();
var result2 = new List<int>();
stp.Start();
for (int i = 0; i < totalElements; i += stepSize)
{
var currentBlock = testList.GetRange(i, stepSize);
result2.Add(currentBlock.Sum());
}
result2.ToList();
stp.Stop();
Console.WriteLine($"Method: GetRange, Time taken: {stp.ElapsedMilliseconds} ms, Elements: {totalElements}, Step Size: {stepSize}");
}
【问题讨论】:
-
只有很小的 sn-ps 很难判断或进一步调查。请提供minimal reproducible example。
-
我不认为这是一般“linq 性能”问题的重复。 26 秒对 9 毫秒是极端的。发生了一些奇怪的事情,可能在我们看不到的代码中。
-
@JonSkeet 我已经添加了我用于测试的完整源代码
-
Skip和GetRange根本不等效,它们的工作方式非常不同。确实,Skip可能应该在source实现IList<T>的情况下进行优化,类似于其他IEnumerable扩展方法的实现方式。不知道他们为什么不这样做...... -
我得到了更适度的差异:~800ms vs ~7ms dotnetfiddle.net/QhjkVA
标签: c# performance linq