C# 如何使异步任务在第一个任务完成后继续执行下一个任务?

C# 如何使异步任务在第一个任务完成后继续执行下一个任务?,c#,asynchronous,async-await,C#,Asynchronous,Async Await,从属任务完成后,如何继续执行下一个任务?是否将Task.ContinueWith()help?如果不是,我如何才能有效地处理以下情况,而不将函数合并为单个函数?假设有4个异步函数: async Task<string> Func1(string a){} async Task<string> Func2(string returnedStringFromFunc1 ){} async Task<string> Func3(string b){} async T

从属任务完成后,如何继续执行下一个任务?是否将
Task.ContinueWith()
help?如果不是,我如何才能有效地处理以下情况,而不将函数合并为单个函数?假设有4个异步函数:

async Task<string> Func1(string a){}
async Task<string> Func2(string returnedStringFromFunc1 ){}
async Task<string> Func3(string b){}
async Task<string> Func4(string returnedStringFromFunc3){}

Task tsk1 = func1("abc");
Task tsk3 = func3("efg");
await tsk1; // In case tsk3 is completed early, flow is waiting here.
    // Instead I could have started tsk4. 
Task tsk2 = func2(tsk1.Result);
await tsk3;
Task tsk4 = func4(tsk3.Result);
async Task Func1(字符串a){}
异步任务Func2(字符串returnedStringFromFunc1){}
异步任务Func3(字符串b){}
异步任务Func4(字符串返回StringFromFunc3){}
任务tsk1=func1(“abc”);
任务tsk3=func3(“efg”);
等待tsk1;//如果tsk3提前完成,流程在此等待。
//相反,我可以启动tsk4。
任务tsk2=func2(tsk1.Result);
等待tsk3;
任务tsk4=func4(tsk3.结果);
您可以使用并根据完成的任务启动下一个任务,然后等待最后一个任务完成

Task tsk1 = func1("abc");
Task tsk3 = func3("efg");
Task tsk2 = null, tsk4 = null;

var completed = await Task.WhenAny(new [] {tsk1, tsk3});
if (completed == tsk1)
{
  tsk2 = func2(tsk1.Result);
  await tsk3;
  tsk4 = func4(tsk3.Result);
}
else
{
  tsk4 = func4(tsk3.Result);
  await tsk1;
  tsk2 = func2(tsk1.Result);
}
您可以使用和,具体取决于完成的任务,启动下一个任务,然后等待最后一个任务完成

Task tsk1 = func1("abc");
Task tsk3 = func3("efg");
Task tsk2 = null, tsk4 = null;

var completed = await Task.WhenAny(new [] {tsk1, tsk3});
if (completed == tsk1)
{
  tsk2 = func2(tsk1.Result);
  await tsk3;
  tsk4 = func4(tsk3.Result);
}
else
{
  tsk4 = func4(tsk3.Result);
  await tsk1;
  tsk2 = func2(tsk1.Result);
}

您可以使用两个单独的函数(甚至本地函数)来组合任务:

async Task<string> Flow1(string input)
{
    var r1=await func1(input);
    var r2=await func2(r1);
    return r2;
}

async Task<string> Flow2(string input)
{
    var r1=await func3(input);
    var r2=await func4(r1);
    return r2;
}

var task1=Flow1("abc");
var task2=Flow2("efg");

await Task.WhenAll(task1,task2);
异步任务流1(字符串输入)
{
var r1=等待功能1(输入);
var r2=等待函数2(r1);
返回r2;
}
异步任务流2(字符串输入)
{
var r1=等待功能3(输入);
var r2=等待函数4(r1);
返回r2;
}
var task1=流量1(“abc”);
var task2=流量2(“efg”);
等待任务。WhenAll(任务1,任务2);

您可以使用两个单独的函数,甚至是本地函数来组合任务:

async Task<string> Flow1(string input)
{
    var r1=await func1(input);
    var r2=await func2(r1);
    return r2;
}

async Task<string> Flow2(string input)
{
    var r1=await func3(input);
    var r2=await func4(r1);
    return r2;
}

var task1=Flow1("abc");
var task2=Flow2("efg");

await Task.WhenAll(task1,task2);
异步任务流1(字符串输入)
{
var r1=等待功能1(输入);
var r2=等待函数2(r1);
返回r2;
}
异步任务流2(字符串输入)
{
var r1=等待功能3(输入);
var r2=等待函数4(r1);
返回r2;
}
var task1=流量1(“abc”);
var task2=流量2(“efg”);
等待任务。WhenAll(任务1,任务2);

尝试加入这些非常有用的扩展方法:

public static class TaskEx
{
    public static async Task<R> Select<T, R>(this Task<T> task, Func<T, R> s)
    {
        var t = await task;
        return s(t);
    }
    public static async Task<R> SelectMany<T, R>(this Task<T> task, Func<T, Task<R>> k) => await k(await task);
    public static async Task<R> SelectMany<T, U, R>(this Task<T> task, Func<T, Task<U>> k, Func<T, U, R> s)
    {
        var t = await task;
        var u = await k(t);
        return s(t, u);
    }
}

尝试加入这些非常有用的扩展方法:

public static class TaskEx
{
    public static async Task<R> Select<T, R>(this Task<T> task, Func<T, R> s)
    {
        var t = await task;
        return s(t);
    }
    public static async Task<R> SelectMany<T, R>(this Task<T> task, Func<T, Task<R>> k) => await k(await task);
    public static async Task<R> SelectMany<T, U, R>(this Task<T> task, Func<T, Task<U>> k, Func<T, U, R> s)
    {
        var t = await task;
        var u = await k(t);
        return s(t, u);
    }
}

这里有一种更为传统的方法,可以使用非常方便的
SelectMany
扩展方法来完成任务:

Task<string> combo12 = Func1("abc").SelectMany(async x => await Func2(x));
Task<string> combo34 = Func3("efg").SelectMany(async x => await Func4(x));
await Task.WhenAll(combo12, combo34); // Await the completion of both workflows
string result12 = await combo12;
string result34 = await combo34;
可以通过异步委托简化代码,如下所示:

Task<string> combo12 = Func1("abc").SelectMany(x => Func2(x));
Task<string> combo34 = Func3("efg").SelectMany(x => Func4(x));
Task<string> combo12 = Func1("abc").SelectMany(Func2);
Task<string> combo34 = Func3("efg").SelectMany(Func4);

如果您想进一步了解
SelectMany
操作符背后的理论,您可能会发现这篇文章很有趣:作者Stephen Toub

这里有一种更为传统的方法,可以对任务使用非常方便的
SelectMany
扩展方法:

Task<string> combo12 = Func1("abc").SelectMany(async x => await Func2(x));
Task<string> combo34 = Func3("efg").SelectMany(async x => await Func4(x));
await Task.WhenAll(combo12, combo34); // Await the completion of both workflows
string result12 = await combo12;
string result34 = await combo34;
可以通过异步委托简化代码,如下所示:

Task<string> combo12 = Func1("abc").SelectMany(x => Func2(x));
Task<string> combo34 = Func3("efg").SelectMany(x => Func4(x));
Task<string> combo12 = Func1("abc").SelectMany(Func2);
Task<string> combo34 = Func3("efg").SelectMany(Func4);

如果您想进一步了解
SelectMany
操作符背后的理论,您可能会发现这篇文章很有趣:作者Stephen Toub

您在ContinueWith()中遇到了什么问题?它似乎很好地宣传了它所做的事情,并且似乎适合你的情况。这似乎是一个xy问题。,可能是你需要await@SnowGroomer如何在ContinueWith中传递上一个任务的输入-我在web上找不到任何示例。@user1066231我发布了一个可能的解决方案,以ContinueWith作为答案-注释很简短。ContinueWith()遇到了什么问题?它似乎很好地宣传了它所做的事情,并且似乎适合你的情况。这似乎是一个xy问题。,可能是你需要await@SnowGroomer如何在ContinueWith中传递上一个任务的输入-我在web上找不到任何示例。@user1066231我已发布了一个可能的解决方案,并将ContinueWith作为答案-注释简短易懂。为获胜而进行的反应式编程@PauloMorgado-它不是反应性的。它只是简单地为LINQ操作符实现正确的重载,以使任务工作。为胜利而进行反应式编程@PauloMorgado-它不是反应性的。它只是为LINQ操作符实现正确的重载以使任务工作。