TPL - 不等待任务

时间:2016-05-25 06:03:09

标签: c# async-await task-parallel-library

使用tpl已经有一段时间了,我还有一些谜团要解决:)

当我在控制台中运行它时,我希望在记录“完成工作”之前完成所有工作:

await StartAttachedAsync(() =>
{
  var result = Parallel.For(0, 4, async i =>
  {
    CallContext.LogicalSetData("ContextId", i);
    await Task.Run(async () =>
    {
       await Task.Delay(2000);
       await Task.Run(async () =>
       {
          await Task.Delay(2000);
          Write("Step C done for i " + i);
       });
       Write("Step B done for i " + i);
     });
     Write("Step A done for i " + i);
   });
   Console.WriteLine("For is done: completed = " + result.IsCompleted);
});
Console.WriteLine("Jobs done");


private static async Task StartAttachedAsync(Action action)
{
   await Task.Factory.StartNew(action,
   CancellationToken.None, 
   TaskCreationOptions.AttachedToParent, 
   TaskScheduler.Default);
}

给我:

For loop is done: completed = True
Jobs done
Step C done for i 0
Step C done for i 2
Step C done for i 3
Step C done for i 1
Step B done for i 1
Step A done for i 1
Step B done for i 0
Step A done for i 0
Step B done for i 3
Step A done for i 3
Step B done for i 2
Step A done for i 2

为什么在没有等待所有子任务的情况下完成循环?

1 个答案:

答案 0 :(得分:1)

因为您使用异步方法执行Parallel.For作为未等待的正文。 所以基本上发生的事情是你在循环结构中启动火灾并忘记任务。

最好保留对您创建的任务的引用,然后执行 await Task.WhenAll(tasks);

你有什么理由使用Parallel.For 。你不能在没有它的情况下创建一堆任务吗?

在您当前的代码中,这样做:

await StartAttachedAsync(() =>
{
    var tasks = new List<Task>();

    var result = Parallel.For(0, 4, async i =>
    {
        CallContext.LogicalSetData("ContextId", i);
        tasks.Add(Task.Run(async () =>
        {
            await Task.Delay(2000);
            await Task.Run(async () =>
            {
                await Task.Delay(2000);
                Write("Step C done for i " + i);
            });
            Write("Step B done for i " + i);
         }));
         Write("Step A done for i " + i);
    });

    await Task.WhenAll(tasks);

    Console.WriteLine("For is done: completed = " + result.IsCompleted);
});