任务继续等待异步lambda

时间:2018-06-26 16:14:33

标签: c# .net multithreading task-parallel-library c#-6.0

当我使用ContinueWith链接一个方法并且如果该方法使用异步Action时,为什么在执行Task.WhenAll时为什么链接的方法没有等待完成?

例如以下代码

var str1 = "str1";
var str2 = "str2";
var task0 = Task.Run( async ()=> { 
                await Task.Delay(1000);
                return "changed";
            });
var task1 = task0.ContinueWith(async prevTask => {
                await Task.Delay(5000);
                str1 = prevTask.Result;
            });
var task2 = task0.ContinueWith(prevTask => {
                Task.Delay(1000).Wait();
                str2 = prevTask.Result;
            });

await Task.WhenAll(task0, task1, task2);
Console.WriteLine(str1);
Console.WriteLine(str2);

产生输出

str1
changed

但是,当我尝试通过异步操作对另一个任务执行相同操作但阻止对Task.Delay的调用时,则该方法可以正常工作。例如,将任务3添加为

....
var str3 = "str3";
var task3 = task0.ContinueWith(async prevTask => {
                Task.Delay(2500).Wait();
                str3 = prevTask.Result;
            });

await Task.WhenAll(task0, task1, task2, task3);
Console.WriteLine(str1);
Console.WriteLine(str2);
Console.WriteLine(str3);

产生以下输出

str1
changed
changed 

在调试时,我还看到task1的状态为“ Ran to complete”,我不明白为什么。似乎在ContinueWith中等待正在导致任务假定任务已完成,但是我不明白为什么?

链接到功能代码:http://rextester.com/WFRTKY13796

1 个答案:

答案 0 :(得分:0)

task1的类型为Task<Task>,因此您需要等待任务以获取结果集。这很容易通过在行中添加await来完成,而第二个示例使用阻塞调用。这是修改后的rexster代码:

//Rextester.Program.Main is the entry point for your code. Don't change it.
//Compiler version 4.0.30319.17929 for Microsoft (R) .NET Framework 4.5

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using System.Threading.Tasks;

namespace Rextester
{
    public class Program
    {
        public static void Main(string[] args)
        {
            Test().Wait();                        
        }

        public static async Task Test(){

            var str1 = "str1_beforeChange";
            var str2 = "str2_beforeChange";
            var str3 = "str3_beforeChange";

            var task0 = Task.Run(async ()=>{
                await Task.Delay(2500);
                return "afterChange";
            });

            //await the async continuation
            var task1 = await task0.ContinueWith(async prevTask => {
                await Task.Delay(5000);
                str1 = prevTask.Result;
            });

            var task2 = task0.ContinueWith(prevTask =>{
                Task.Delay(2500).Wait();
                str2 = prevTask.Result;
            });

            var task3 = task0.ContinueWith(prevTask =>{
                Task.Delay(1000).Wait();
                str3 = prevTask.Result;
            });

            await Task.WhenAll(task0, task1, task2, task3);

            Console.WriteLine(str1);
            Console.WriteLine(str2);
            Console.WriteLine(str3);
        }
    }
}