启动异步操作,然后等待

本文关键字:等待 然后 异步操作 启动 | 更新日期: 2023-09-27 18:32:12

我现在才开始玩异步和等待。 我有 8 个单独的数据库调用,其中一些依赖于其他调用。 我希望能够启动 3 个异步方法,然后当某个 1 返回时,启动其他 3 个,然后当某个 1 从中返回时,再启动 2 个。 我目前正在使用 3 个 Parallel.Invoke 方法来完成此操作,但每个并行都必须等到所有方法返回。 我只关心 1 个方法返回,其他方法可以在后台运行,直到最后await Task.WhenAll(t1,t2,t3,...,t6)有没有办法用异步/等待来做到这一点?

我知道 await 不是阻塞,但它会停止执行我的主方法(带有 8 db 调用),直到值从该方法返回(就像同步方法一样)。

启动异步操作,然后等待

您可以使用

Task.WhenAny来等待以下几个任务中的任何一个:

var completedTask = await Task.WhenAny(t1, t2, t3, ...);

如果你有一个更复杂的依赖结构,那么我建议用async方法表示它:

static async Task DoMasterOperationAsync()
{
  var result = await StartSomething();
  await Task.WhenAll(DoComplexOperationAsync(), result.NextT1Async());
}
static async Task DoComplexOperationAsync()
{
  var result1 = await T1Async();
  await Task.WhenAll(result1.NextT1Async(), result1.NextT2Async(), result1.NextT3Async());
}
await Task.WhenAll(DoMasterOperationAsync(), t2, t3, ...);

我的问题是我不知道Task.Run可以让你开始一个任务,然后等待它。 我在@StephenCleary的另一个答案中找到了这一点。 谢谢斯蒂芬,你在那里得到了我的赞成票! 这是我完全人为的例子,它完成了我上面设定的任务:

        Func<Task<int>> t1 = async () => { await Task.Delay(4000); return 1; };
        Func<Task<int>> t2 = async () => { await Task.Delay(5000); return 2; };
        Func<int, Task<int>> t3 = async (val) => { await Task.Delay(3000); return 3; };
        Func<int, Task<int>> t4 = async (val) => { await Task.Delay(4000); return 4; };
        Func<int, Task<int>> t5 = async (val) => { await Task.Delay(3000); return 5; };
        Func<int, Task<int>> t6 = async (val) => { await Task.Delay(2000); return 6; };
        Func<int, Task<int>> tSecondary = async (val) => { await Task.Delay(3000); return 7; };
        Func<Task<int>> tPrimary = async () => { await Task.Delay(2000); return 8; };
        //kick off first 3 calls
        var primaryR = Task.Run(tPrimary);
        var t1R = Task.Run(t1);
        var t2R = Task.Run(t2);
        //await 1 of the 3
        var primary = await primaryR;
        //start 2 of 3 dependent tasks
        var t3R = Task.Run(() => t3(primary));
        var t4R = Task.Run(() => t4(primary));
        //kick off and await secondaryMasterTaskAsync
        var secondary = await tSecondary(primary);
        //start final 2
        var t5R = Task.Run(() => t5(secondary));
        var t6R = Task.Run(() => t6(secondary));
        //await all tasks that haven't been awaited previously
        var tasks = await Task.WhenAll(t1R, t2R, t3R, t4R, t5R, t6R);