C# C Task.run(),将参数传递给
考虑以下代码C# C Task.run(),将参数传递给,c#,asynchronous,concurrency,task,C#,Asynchronous,Concurrency,Task,考虑以下代码 attempt = 0; for (int counter = 0; counter < 8; counter++) { if (attempt < totalitems) { Tasklist<output>.Add(Task.Run(() => { return someasynctask(inputList[attempt]); })); }
attempt = 0;
for (int counter = 0; counter < 8; counter++)
{
if (attempt < totalitems)
{
Tasklist<output>.Add(Task.Run(() =>
{
return someasynctask(inputList[attempt]);
}));
}
else
{
break;
}
attempt++;
}
await Task.WhenAll(Tasklist).ConfigureAwait(false);
例如,我希望有8个并发任务,每个任务同时处理不同的输入,最后在所有任务完成后检查结果。
因为我没有等待任务完成。在开始任务之前,运行尝试会增加,并且当任务启动时,由于尝试值的不确定性,inputlist中可能存在未处理或未处理两次或两次以上的项
如何做到这一点?问题在于lambda的使用:when Task.Run=>return someasynctaskinputList[trust];在执行过程中到达,则捕获变量尝试,而不是其值,即它是一个闭包。因此,当执行lambda时,将使用该特定时刻的变量值 只需在lambda之前添加变量的临时副本,并使用它。例如
if (attempt < totalitems)
{
int localAttempt = attempt;
Tasklist<output>.Add(Task.Run(() =>
{
return someasynctask(inputList[localAttempt]);
}));
}
问题在于lambda的使用:when Task.Run=>return someasynctaskinputList[trunt];在执行过程中到达,则捕获变量尝试,而不是其值,即它是一个闭包。因此,当执行lambda时,将使用该特定时刻的变量值 只需在lambda之前添加变量的临时副本,并使用它。例如
if (attempt < totalitems)
{
int localAttempt = attempt;
Tasklist<output>.Add(Task.Run(() =>
{
return someasynctask(inputList[localAttempt]);
}));
}
感谢@gobes的回答: 试试这个:
attempt = 0;
for (int counter = 0; counter < 8; counter++)
{
if (attempt < totalitems)
{
Tasklist<output>.Add(Task.Run(() =>
{
int tmpAttempt = attempt;
return someasynctask(inputList[tmpAttempt]);
}));
}
else
{
break;
}
attempt++;
}
await Task.WhenAll(Tasklist).ConfigureAwait(false);
实际上,编译器所做的是将lambda提取到一个方法中,该方法位于自动生成的类中,该类引用了尝试变量。这一点很重要:生成的代码只引用另一个类中的变量;它不会复制它。因此,尝试的每一个变化都可以通过该方法看到
执行过程中发生的情况大致如下:
输入尝试为0的循环
将lambda-like方法的调用添加到任务列表中
增加尝试
重复
在循环之后,您有一些方法调用等待执行,但是每个方法调用都引用同一个变量,因此共享它的值——最后一个受影响的变量
要了解更多详细信息,我真的建议您深入阅读C或类似的书籍-web上有很多关于C闭包的资源:感谢@gobes的回答: 试试这个:
attempt = 0;
for (int counter = 0; counter < 8; counter++)
{
if (attempt < totalitems)
{
Tasklist<output>.Add(Task.Run(() =>
{
int tmpAttempt = attempt;
return someasynctask(inputList[tmpAttempt]);
}));
}
else
{
break;
}
attempt++;
}
await Task.WhenAll(Tasklist).ConfigureAwait(false);
实际上,编译器所做的是将lambda提取到一个方法中,该方法位于自动生成的类中,该类引用了尝试变量。这一点很重要:生成的代码只引用另一个类中的变量;它不会复制它。因此,尝试的每一个变化都可以通过该方法看到
执行过程中发生的情况大致如下:
输入尝试为0的循环
将lambda-like方法的调用添加到任务列表中
增加尝试
重复
在循环之后,您有一些方法调用等待执行,但是每个方法调用都引用同一个变量,因此共享它的值——最后一个受影响的变量
要了解更多详细信息,我真的建议您深入阅读C或类似的书籍-web上有很多关于C闭包的资源:您应该提供一个MCVE。。。无论如何,正如我理解你所说的,你的问题是变量尝试在你开始任务时没有预期的值,对吗?PLINQ可能会有帮助。是的,你是对的!尝试值的更改比启动任务@gobesIsn要快得多这不是一个与闭包相关的问题吗?看看这里:你应该提供一个MCVE。。。无论如何,正如我理解你所说的,你的问题是变量尝试在你开始任务时没有预期的值,对吗?PLINQ可能会有帮助。是的,你是对的!尝试值的更改比启动任务@gobesIsn要快得多这不是一个与闭包相关的问题吗?看看这里:你能告诉我怎么做吗?我在lambada内部创建了一个副本,现在它可以工作了,但仍然是一个问题?该解决方案是否始终有效,或者有时可能存在一些不一致性?应在lambda本身中声明“localtrunt”以强制复制该值;在您的代码中仍然存在闭包问题。我不知道什么是闭包问题:csharpindepth.com/Articles/Chapter5/Closures.aspx中有很多内容需要阅读。我想要一个更简单的教程@gobesCould你能告诉我怎么做吗?我在lambada内部创建了一个副本,现在它可以工作了,但还是一个问题?该解决方案是否始终有效,或者有时可能存在一些不一致性?应在lambda本身中声明“localtrunt”以强制复制该值;在您的代码中仍然存在闭包问题。我不知道什么是闭包问题:csharpindepth.com/Articles/Chapter5/Closures.aspx中有很多内容需要阅读。我想要一个更简单的教程@gobesint tmpatempt=trunt;应该在任务之上。运行,对吗?对于在这里绊倒的人,最好滚动到下一个答案。这个答案是错误的。请参见此图。int tmpatempt=trunt;应该在任务之上。R 联合国,对吗?对于在这里绊倒的人,最好滚动到下一个答案。这个答案是错误的。看这个。