不同的任务方法的工作方式不同[重复]
Posted
技术标签:
【中文标题】不同的任务方法的工作方式不同[重复]【英文标题】:Different Task approaches work differently [duplicate] 【发布时间】:2021-08-16 09:45:45 【问题描述】:我想问一下为什么这两种方法不同,并返回两组不同的值:
在我看来正确的第一个返回值从 0 到 8 并且适用于不同的线程(LINQPad 代码):
void Main()
var newTasks = Enumerable.Range(0, 9).Select(x => Task.Run(() => DoSomething(x)));
Task.WhenAll(newTasks);
public int DoSomething(int value)
return value;
其次,我认为这是不正确的,它返回随机值特别是 9,但也适用于不同的线程。
void Main()
var tasks = new List<Task<int>>();
for (var index = 0; index < 9; index++)
var task = Task.Run(() => DoSomething(index));
tasks.Add(task);
Task.WaitAll(tasks.ToArray());
public int DoSomething(int value)
return value;
是否可以修改第二个并获得类似于第一个示例的结果?
感谢您的回答。
【问题讨论】:
相关:Captured variable in a loop in C# 【参考方案1】:是否可以修改第二个并获得类似于第一个示例的结果?
当您将变量或对象传递给Task.Run(()=> DoSomething(index))
时,您捕获一个变量。
从某种意义上说,您不仅仅是将该变量作为值或对象发送,而是让该线程直接访问原始变量。 (这是高度概括的,并且有很多细微差别)。
您最有可能遇到的问题是 CLR 正在尝试捕获 index
,这是一个 迭代器,其范围不能离开其边界,除非任何尝试这样做都会保留在堆栈中(基本上相同的线程,再次概括)。
当 CLR '捕获'index
时,它只会捕获 index
曾经的随机值(由于竞争条件) - 或 index
曾经的 last 值,即double 不直观,因为您明确告诉它 index
永远不应在此行中到达 9
for (var index = 0; index < 9; index++)
。
这是一个棘手的问题,当 CLR 捕获 index
时,它会捕获 index
的最后一个值。但是在循环结束后,index
再增加一次,导致9
成为index
的最后一个值。
这可能会导致一大堆问题,尤其是在您使用数组时,我们来IndexOutOfBoundsException
!
如何解决
修复其实超级简单!只需在循环中创建一个临时变量,然后直接传递它而不是 index
。
这是一个例子:
void Main()
var tasks = new List<Task<int>>();
for (var index = 0; index < 9; index++)
int tmpIndex = index;
var task = Task.Run(() => DoSomething(tmpIndex ));
tasks.Add(task);
Task.WaitAll(tasks.ToArray());
是否可以修改第二个并获得类似于第一个示例的结果?
旁注永远不要依赖任务中的数据按顺序排列,除非您明确实施了保证项目按顺序返回的保证。 TaskScheduler
选择 Tasks
以在 FIFO 中正常运行(先进先出),但是,如果 TaskScheduler
优化、优先排序或转移任务(经常这样做)你的任务将不按顺序完成,随后您获得的结果也将不按顺序完成。
【讨论】:
以上是关于不同的任务方法的工作方式不同[重复]的主要内容,如果未能解决你的问题,请参考以下文章