所以我有这样的方法。
var someColletion = _someService.GetSomeCollection(someParam);
var taskCollection = new Task<double>[someCollection.Count];
for (int i = 0; i < taskCollection.Length; i++)
{
// do some stuff on the i-th element of someCollection and taskCollection
// and start the i-th task
}
Task.WaitAll(taskCollection);
double total = 0;
for (int i = 0; i < taskCollection.Length; i++)
{
// get the result of each task and sum it in total variable
}
return total;
这种情况是当它进入第一个for循环并且两个集合中的元素数量假设为1时抛出ArgumentOutOfRangeException
然后在Task.WaitAll()
上抛出AggregateException,因为{{1}变成1(我不知道为什么,但确实如此)当它试图访问仅包含一个元素的数组中的第i个(第二个)元素时,就会发生这种情况。但还有更多。如果我在第一个循环之前设置一个断点并逐步进行,那么这个事情就不会发生。当i
成为一个时,循环结束。一切都没问题。现在我上面提供的方法是由ASP.NET MVC Controller的Action调用的,它本身被称为Asynchronously(通过ajax调用)假设3次。在这三个中只有一个正确执行其他两个做我上面说过的事情(如果没有断点)。我认为这个问题是由ajax调用引起的,因为当我断点时它会阻止其他调用执行。谁能提出任何建议?
答案 0 :(得分:4)
我怀疑您在第一个循环中使用i
,使用lambda表达式或匿名方法捕获它,如下所示:
for (int i = 0; i < taskCollection.Length; i++)
{
taskCollection[i] = Task.Run(() => Console.WriteLine(i));
}
如果是这种情况,那就是正在捕获的变量 i
- 而不是循环迭代的变量值。因此,当任务实际执行时,i
的值可能已发生变化。解决方案是在循环中,在单独的“new”变量中获取迭代变量的副本,并在匿名函数中捕获它:
for (int i = 0; i < taskCollection.Length; i++)
{
int copy = i;
taskCollection[i] = Task.Run(() => Console.WriteLine(copy));
}
这样,每个任务都会捕获一个单独的变量,其值永远不会改变。