C# 不同的任务方法工作方式不同
我想问一下,为什么这两种方法不同,并返回两组不同的值: 我认为第一个是正确的,它返回0到8之间的值,并在不同的线程上工作(LINQPad代码): 第二,在我看来这是不正确的,它返回的随机值是9,但也适用于不同的线程C# 不同的任务方法工作方式不同,c#,.net,multithreading,asynchronous,task,C#,.net,Multithreading,Asynchronous,Task,我想问一下,为什么这两种方法不同,并返回两组不同的值: 我认为第一个是正确的,它返回0到8之间的值,并在不同的线程上工作(LINQPad代码): 第二,在我看来这是不正确的,它返回的随机值是9,但也适用于不同的线程 void Main() { var tasks = new List<Task<int>>(); for (var index = 0; index < 9; index++) { var task =
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;
}
void Main()
{
var tasks=新列表();
对于(var指数=0;指数<9;指数++)
{
var task=task.Run(()=>DoSomething(index));
任务。添加(任务);
}
Task.WaitAll(tasks.ToArray());
}
公共整数剂量测量(整数值)
{
返回值;
}
是否可以修改第二个,得到与第一个示例类似的结果
谢谢你的回答
是否可以修改第二个,得到与第一个示例类似的结果
当您将变量或对象传递到Task.Run(()=>DoSomething(index))
中时,您将捕获一个变量
从某种意义上说,您不仅仅是将该变量作为值或对象发送,而是让该线程直接访问原始变量。(这是高度概括的,有很多细微差别)
您最可能遇到的问题是CLR试图捕获索引
,这是一个迭代器,它的作用域不能离开它的边界,除非任何这样做的尝试都会保留在堆栈上(基本上是同一个线程,也是过度泛化的)
当CLR“捕获”index
时,它将只捕获index
是(由于种族条件)的随机值,或index
是的最后一个值,这是双非直观的,因为您明确告诉它index
永远不会到达9
(var index=0;index<9;index++)
这里有一件棘手的事情,当CLR捕获index
时,它捕获index
的最后一个值。但是循环结束后,index
再次递增,导致9
成为index
的最后一个值
这可能会导致一系列问题,特别是当您使用数组时,我们来看看IndexOutOfBoundsException
如何修复它修复实际上非常简单!只需在循环中创建一个临时变量,并传递它,而不是直接传递
索引
下面是一个例子:
void Main()
{
var tasks=新列表();
对于(var指数=0;指数<9;指数++)
{
int tmpIndex=索引;
var task=task.Run(()=>DoSomething(tmpIndex));
任务。添加(任务);
}
Task.WaitAll(tasks.ToArray());
}
是否可以修改第二个,得到与第一个示例类似的结果
旁注
切勿依赖任务中的数据来保持有序,除非您明确实施了保证项目恢复有序的措施。TaskScheduler
选择tasks
在FIFO中正常运行(先进先出),但是,如果TaskScheduler
对任务进行优化、优先排序或转移(这是经常发生的)你的任务不会按顺序完成,随后你得到的结果也不会按顺序完成。相关:
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;
}