【问题标题】:Why does this task-generating loop never stop? [duplicate]为什么这个任务生成循环永远不会停止? [复制]
【发布时间】:2017-06-20 15:41:06
【问题描述】:

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

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 万的目标时,它会继续前进。

但是为什么呢?

【问题讨论】:

标签: c# task


【解决方案1】:

这是classic loop-variable closure problem in C#

您的循环确实在一百万处停止。

在它停止在一百万之后,您对WriteHelloAsync(i) 进行了大量调用。

您将i 传递给他们所有人。您传递给Task.Run() 的那个lambda 并没有创建i 的新副本,该副本在特定调用Task.Run() 时保存值ihad。它们都有相同的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));
}

【讨论】:

  • 闭包很神奇。您能否提及确定为什么变量被重用的机制?
  • 这是一个闭包。我不明白。它在那里。这是i。有一个i
  • 我以为我已经掌握了闭包。总是感激能学到新东西!
  • @EdPlunkett 我看到该答案的 cmets 对此进行了解释。它在 VS2012 中已修复,但仅在使用 foreach 时才修复。 for 循环仍然会表现出这种行为。
  • @Gigi Dang!现在我正在学习新东西!
猜你喜欢
  • 1970-01-01
  • 2021-11-28
  • 2018-08-14
  • 2016-03-16
  • 2013-09-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-06-10
相关资源
最近更新 更多