的任务.继续和我预想的不一样

本文关键字:不一样 任务 继续 | 更新日期: 2023-09-27 18:05:03

考虑以下代码。我从一个什么都不做的任务开始,然后使用ContinueWith()开始10次调用一个增加计数器的方法。

当我运行这个程序时,它打印"0",表示根本没有调用increment()方法。我希望它被调用10次,因为这是我调用ContinueWith()的次数。

如果我取消注释"Thread.Sleep(20)"行,那么它会像预期的那样打印"10"。

这在发布或调试模式下都会发生。我的系统是一个core 2 quad,带有超线程(8个逻辑内核),运行Windows 7 x64。

我想我对Task.ContinueWith()的工作方式有一些基本的误解....

using System;
using System.Threading;
using System.Threading.Tasks;
namespace ConsoleApplication4
{
    class Program
    {
        static void Main()
        {
            using (var task = Task.Factory.StartNew(()=>{}))
            {
                for (int i = 0; i < 10; ++i)
                {
                    task.ContinueWith(_=> increment());
                    // Thread.Sleep(20);  // Uncomment to print 10 instead of 0.
                }
                task.Wait();
            }
            // This prints 0 UNLESS you uncomment the sleep above.
            Console.WriteLine(counter); 
        }
        static void increment()
        {
            Interlocked.Increment(ref counter);
        }
        private static int counter;
    }
}

谁能解释一下这里发生了什么?

的任务.继续和我预想的不一样

原因很简单:等待已经完成的任务。您真正想要的是等待在循环中创建的十个任务:

var tasks = new List<Task>();
for (int i = 0; i < 10; ++i)
{
    tasks.Add(task.ContinueWith(_=> increment()));
}
Task.WaitAll(tasks.ToArray());

当然。当初始任务完成时,您将打印出该值—而不是等待执行延续。换句话说,当初始任务完成时,会发生11件事:

  • 10个新任务开始执行,每个任务增加计数器
  • 你打印出计数器

如果你愿意,你可以有效地将所有这些链接在一起:

task = task.ContinueWith(_=> increment());

当原始任务完成时,将触发一个增量。当完成时,将触发下一个增量。当那结束时[…]。当最后一个增量完成后,您的Wait调用将返回。

如果按如下方式更改主体:

        using (var task = Task.Factory.StartNew(() => { }))
        {
            var t = task;
            for (int i = 0; i < 10; ++i)
            {
               t = t.ContinueWith(_ => increment());
                // Thread.Sleep(20);  // Uncomment to print 10 instead of 0.
            }
            t.Wait();
        }

你不睡觉就会得到10。主要的改变是t = t.ContinueWith(...)t是必要的,因为你不允许改变using()变量。