为什么这个任务生成循环永远不会停止?

时间:2017-06-20 15:41:06

标签: c# task

非常简单的场景。我正在运行一个紧凑的循环,每次迭代都会生成任务。 (不要问为什么。)

static void Main(string[] args)
{
    for (int i = 0; i < 1000 * 1000; i++)
        Task.Run(() => WriteHelloAsync(i));

    Console.ReadLine();
}

static Task WriteHelloAsync(int x)
{
    Console.WriteLine($"Hello {x}!");

    return Task.CompletedTask;
}

我可以在控制台中看到它以递增方式写入迭代编号。然而,当它达到目标100万时,它就会继续前进。

enter image description here

但为什么?

1 个答案:

答案 0 :(得分:2)

这是classic loop-variable closure problem in C#

你的循环确实停止了一百万。

在百万停止后,你会拨打大量的WriteHelloAsync(i)电话。

您将i传递给所有人。您传递给Task.Run()的lambda不会创建i的新副本,该副本保留i 时的值{/ 1>特别致电Task.Run()。它们都具有相同的i,其值不断变化,直到循环结束。

在我的机器上,我看到的第一个数字是六位数,这意味着i的值是第一次任务实际到达调用WriteHelloAsync()时的值。此后不久,它开始做你看到的数百万美元的事情。

试试这个:

static void Main(string[] args)
{
    for (int i = 0; i < 1000 * 1000; i++)
    {
        //  The scope of j is limited to the loop block.
        //  For each new iteration, there is a new j. 
        var j = i;
        Task.Run(() => WriteHelloAsync(j));
    }

    Console.ReadLine();
}

@Gigi指出,这也适用于foreach而不是for

foreach (var i in Enumerable.Range(0, 1000 * 1000))
{
    Task.Run(() => WriteHelloAsync(i));
}