For 循环中的异步任务 运行:System.ArgumentOutOfRangeException
Asynchronous Task Run in a For Loop: System.ArgumentOutOfRangeException
我对编程还很陌生,因此决定测试一个涉及异步执行数组排序任务的想法。我几乎是异步编程的新手,并且 运行 遇到了一个错误,该错误似乎只能通过某种奇怪的异步...东西...发生来解释。
当我通过以下代码对其进行调试时,它运行良好。但是,当我允许它自由 运行 时,我 运行 进入参数超出范围异常:我变得大于 allArrays.Count - 1,并且程序失败。然而
if (i >= allArrays.Count) Console.WriteLine($"i is too high! i = {i}");
行在失败之前从不执行。有人可以向我解释一下,并帮助提出解决这个问题的方法吗?
谢谢!
//iterate while allArrays contains multiple arrays to be merged.
while (allArrays.Count > 1)
{
if (allArrays.Count % 2 != 0)//if it's not even, we add one and make it even, so every array has a partner!
{
allArrays.Add(new int[0]);
}
for (int i = 0; i < allArrays.Count - 1; i+=2)
{
Console.WriteLine($"i is {i}");
if (i >= allArrays.Count) Console.WriteLine($"i is too high! i = {i}");
mergeTasks.Add(Task.Run(() => Merge(allArrays[i], allArrays[i + 1])));
}
await Task.WhenAll(mergeTasks);
//empty the list of smaller arrays
allArrays.Clear();
//add results to all arrays then empty mergeTasks
mergeTasks.ForEach(r => allArrays.Add(r.Result));
mergeTasks.Clear();
}
添加临时变量来存储 i
并在 lambda 中将其用于任务:
for (int i = 0; i < allArrays.Count - 1; i+=2)
{
var tmp = i; // create copy of current i
Console.WriteLine($"i is {i}");
if (i >= allArrays.Count) Console.WriteLine($"i is too high! i = {i}");
// use tmp here instead of i:
mergeTasks.Add(Task.Run(() => Merge(allArrays[tmp], allArrays[tmp + 1])));
}
Task.Run
接受 lambda。要从外部范围使用变量,它将创建所谓的闭包。对于 for
循环,使用相同的闭包实例,因此捕获的值可以更改,因此它有可能在您的最后一个任务调用 [= 之前更改为最后一个值(即 i > allArrays.Count - 1
) 16=]导致问题出现异常。
您可以尝试“验证”此行为,例如:
mergeTasks.Add(Task.Run(() => {
if (i >= allArrays.Count) Console.WriteLine($"i is too high! i = {i}");
return Merge(allArrays[tmp], allArrays[tmp + 1]);
}));
您可以通过 this article or this 问题进行更深入的研究。
我对编程还很陌生,因此决定测试一个涉及异步执行数组排序任务的想法。我几乎是异步编程的新手,并且 运行 遇到了一个错误,该错误似乎只能通过某种奇怪的异步...东西...发生来解释。
当我通过以下代码对其进行调试时,它运行良好。但是,当我允许它自由 运行 时,我 运行 进入参数超出范围异常:我变得大于 allArrays.Count - 1,并且程序失败。然而
if (i >= allArrays.Count) Console.WriteLine($"i is too high! i = {i}");
行在失败之前从不执行。有人可以向我解释一下,并帮助提出解决这个问题的方法吗?
谢谢!
//iterate while allArrays contains multiple arrays to be merged.
while (allArrays.Count > 1)
{
if (allArrays.Count % 2 != 0)//if it's not even, we add one and make it even, so every array has a partner!
{
allArrays.Add(new int[0]);
}
for (int i = 0; i < allArrays.Count - 1; i+=2)
{
Console.WriteLine($"i is {i}");
if (i >= allArrays.Count) Console.WriteLine($"i is too high! i = {i}");
mergeTasks.Add(Task.Run(() => Merge(allArrays[i], allArrays[i + 1])));
}
await Task.WhenAll(mergeTasks);
//empty the list of smaller arrays
allArrays.Clear();
//add results to all arrays then empty mergeTasks
mergeTasks.ForEach(r => allArrays.Add(r.Result));
mergeTasks.Clear();
}
添加临时变量来存储 i
并在 lambda 中将其用于任务:
for (int i = 0; i < allArrays.Count - 1; i+=2)
{
var tmp = i; // create copy of current i
Console.WriteLine($"i is {i}");
if (i >= allArrays.Count) Console.WriteLine($"i is too high! i = {i}");
// use tmp here instead of i:
mergeTasks.Add(Task.Run(() => Merge(allArrays[tmp], allArrays[tmp + 1])));
}
Task.Run
接受 lambda。要从外部范围使用变量,它将创建所谓的闭包。对于 for
循环,使用相同的闭包实例,因此捕获的值可以更改,因此它有可能在您的最后一个任务调用 [= 之前更改为最后一个值(即 i > allArrays.Count - 1
) 16=]导致问题出现异常。
您可以尝试“验证”此行为,例如:
mergeTasks.Add(Task.Run(() => {
if (i >= allArrays.Count) Console.WriteLine($"i is too high! i = {i}");
return Merge(allArrays[tmp], allArrays[tmp + 1]);
}));
您可以通过 this article or this 问题进行更深入的研究。