在我的程序中,我目前有类似的结构:
bash
它无法正常工作,因为函数for (int i=0; i<MyCollection.Count; i++)
{
Task.Factory.StartNew(()=>
{
DoStuffWith(MyCollection[i]);
DoEvenMoreStuffWith(MyCollection[i]);
});
}
和DoStuffWith()
比DoEvenMoreStuffWith()
花费更多时间来完成,因此其中一个通常会修改集合的错误元素。
我知道我不能在i++
之前int a = i
,因为它会一样,真的。
如何确保每个线程都使用自己的索引?
P.S。:抱歉,我试着在这里寻找答案,但我甚至不知道如何正确地进行谷歌搜索。我知道它与引用类型和值类型有关,但我之前从未在Task.Factory
周围使用它们。
答案 0 :(得分:2)
如果你使用标准 for
循环,你可以在循环体的闭包内保留变量的本地副本(正如你所建议的那样),这个关闭将由您的延期代码的正文捕获。
所以:
for (int i=0; i<MyCollection.Count; i++)
{
var a = i;
Task.Factory.StartNew(()=>
{
DoStuffWith(MyCollection[a]);
DoEvenMoreStuffWith(MyCollection[a]);
});
}
但是,还有更好的方法。
最近(ish),the c# language was changed to close over the loop variable in foreach
loops。
所以,除非你坚持使用2012年的工具,否则现在你可以:
foreach(var item in MyCollection)
{
Task.Factory.StartNew(()=>
{
DoStuffWith(item);
DoEvenMoreStuffWith(item);
});
}
没有发生这个问题。
顺便说一句,你知道difference between Task.Factory.StartNew
and Task.Run
吗?你应该这样做。