.Net 4.0 中的任务

Task in .Net 4.0

我正在尝试使用 .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.

我哪里错了?

您在定义函数 () => DoSomething(i.ToString()) 时创建了一个 closure

闭包是一个匿名的 function/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);
}

尽管如此,您不应该期望结果以任何特定顺序排列。

您正在访问一个在循环中发生变化的变量。本质上,你的 foreach 运行s 如此之快,到 DoSomething 运行s 时,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 都是 运行 独立的彼此的。