通过Continuewith捕获多个Task回调

本文关键字:Task 回调 Continuewith 通过 | 更新日期: 2023-09-27 18:27:06

我想同时运行多个任务。每个任务都将返回一个值类型。

有人能告诉我如何通过ContinueWith捕捉所有的回调吗?

我的测试代码:

        static async Task<List<string>> ListAsync()
        {
            await Task.Delay(1000);
            return new List<string>() { "Item 1", "Item 2" };
        }
        static async Task<int> IntAsync()
        {
            await Task.Delay(1000);
            return 10;
        }
        static async Task<string> StringAsync()
        {
            await Task.Delay(1000);
            return "My string";
        }
        static async Task Test()
        {
            Task t1 = StringAsync();
            Task t2 = IntAsync();
            Task t3 = ListAsync();
            await Task.WhenAny(t1, t2, t3).ContinueWith(t =>
            {
                //how can I catch callbacks here?
            });
        }

通过Continuewith捕获多个Task回调

如果您试图检索所有任务的结果,一旦它们全部完成,您可以简单地使用Task.WhenAll。如果所有任务都返回相同的结果,则Task.WhenAll(Task[]重载将返回一个Task。在这种情况下,await Task.WhenAll将返回带有任务结果的数组,顺序为:

var t1=Task.Run(()=>{...;return 1});
var t2=Task.Run(()=>{...;return 2});
var t3=Task.Run(()=>{...;return 3});
int[] results=await Task.WhenAll(t1,t2,t3);
//Check t1's result
Debug.Assert(results[0]==1);

当任务返回不同的结果时,会调用Task.WhenAll(params Task[]),它只返回一个Task。不过,您仍然可以使用其Result属性访问每个任务的结果,而不会有任何阻塞风险:

var t1=Task.Run(()=>{...;return 1});
var t2=Task.Run(()=>{...;return "Hi"});
var t3=Task.Run(()=>{...;return new[]{1,2,3}});
await Task.WhenAll();
Debug.Assert(t2.Result=="Hi");

在使用await时,没有理由使用ContinueWith,因为等待与使用ContinueWith大致相同-它不启动任何异步执行,它在等待时不会阻止已经运行的任务完成,它提取结果并将同步上下文设置为等待启动前的状态。

如果不想调用具有不同延续的任务,则需要为每个任务指定延续:

static async Task Test()
{
    Task t1 = StringAsync().ContinueWith(t => System.Console.Out.WriteLine("string"));
    Task t2 = IntAsync().ContinueWith(t => System.Console.Out.WriteLine("int"));
    Task t3 = ListAsync().ContinueWith(t => System.Console.Out.WriteLine("list"));
    await Task.WhenAny(t1, t2, t3); 
    // use WhenAll if you want to wait until all tasks are done
}

WhenAny将在任何子任务完成时完成,然后触发continuation,因此continuation将只调用一次。

如果你想在所有任务完成后调用回调一次,最简单的方法是:

static async Task Test()
{
    Task t1 = StringAsync();
    Task t2 = IntAsync();
    Task t3 = ListAsync();
    await Task.WhenAll(t1, t2, t3); 
    // your continuation logic here
}