我尝试使用.Net 4.0 c#中的Task进行并行编程。
我的程序输出有点混乱。
class Program
{
static void Main(string[] args)
{
List<Task> lstTasks = new List<Task>();
for (int i = 0; i < 5; i++)
{
Task tsk = Task.Factory.StartNew(() => DoSomething(i.ToString()));
lstTasks.Add(tsk);
}
Task.WaitAll(lstTasks.ToArray());
Console.WriteLine("Done");
Console.ReadLine();
}
static void DoSomething(string tasKname)
{
Console.WriteLine(tasKname);
System.Threading.Thread.Sleep(10000);
}
}
输出
5
5
5
5
5
Done.
我期待。
0
1
2
3
4
Done.
我出错了?
答案 0 :(得分:2)
您在定义函数() => DoSomething(i.ToString())
时创建了closure。
闭包是一个匿名函数/ lamdba,它引用了创建闭包的方法中定义的一些变量。在您的情况下,这是变量i
。
执行此功能时,它将使用i
的当前值,而不是i
创建时的值。
您必须知道调用Task.Factory.StartNew
不会立即开始执行任务。在您的情况下,任务在for
循环后开始执行,因此i
的值为5。
要获得预期的结果,请在循环中使用单独的变量来存储i
的当前值。
for (int i = 0; i < 5; i++)
{
int k = i;
Task tsk = Task.Factory.StartNew(() => DoSomething(k.ToString()));
lstTasks.Add(tsk);
}
你不应该以任何特定的顺序期待结果。
答案 1 :(得分:2)
您正在访问正在循环中更改的变量。从本质上讲,您的foreach
运行速度非常快,在DoSomething
运行时,i
为5.尝试此操作:
for (int i = 0; i < 5; i++)
{
Task tsk = Task.Factory.StartNew(() => DoSomething(i.ToString()));
lstTasks.Add(tsk);
Thread.Sleep(50);
}
你应该在控制台中看到你的预期输出。
你说I'm expecting 0 1 2 3 4
。但你不应该。任务最重要的方面是你不知道什么时候完成。例如,当我更改代码以使用Parallel.Foreach()时:
Parallel.ForEach(Enumerable.Range(0, 5), i =>
{
Task tsk = Task.Factory.StartNew(() => DoSomething(i.ToString()));
lstTasks.Add(tsk);
});
我得到了预期的数字,0到4,但每次运行代码时都是随机顺序,因为我们使用的Tasks
都是相互独立运行的。{/ p>