对多个异步调用的反应不同

react different to multiple async calls

想象一下以下场景:

public async Task DoMultipleWork() {
    var uploadTask = UploadAsync(file);
    var processingTask = Task.Run( () => DoCpuWork() );

    await Task.WhenAll(uploadTask, processingTask);
    Console.WriteLine("upload is done");
    Console.WirteLine("processing is done");
}

我如何更改该代码,以便无论哪个代码先结束,它都执行一些特定的(同步或异步)代码。

所以我触发了两个任务,当 taskAtaskB 结束时,我只是 运行 一些独立于其他代码(同步或异步)的代码。

我想也许 ContinueWith 但我不确定,因为它需要另一个实际上并不需要的异步方法。

编辑 正如对答案的评论所建议的那样,我想明确我想根据完成的任务执行不同的代码,并在原始任务完成后立即执行这两个 Console.WriteLine。

您想使用 Task.WhenAny 其中 returns 第一个完成的任务。然后,您可以通过与原始任务进行比较来判断完成了哪个任务。在返回之前,您应该等待另一个显式完成(或使用 Task.WhenAll 等待两者):

public async Task DoMultipleWork() 
{
    var uploadTask = UploadAsync(file);
    var processingTask = Task.Run( () => DoCpuWork() );

    var completedTask = await Task.WhenAny(uploadTask, processingTask);
    Console.WriteLine("upload or processing is done");
    if (completedTask == uploadTask)
    {
        // Upload completed
    }
    else
    {
        // Processing completed
    }

    await Task.WhenAll(uploadTask, processingTask) // Make sure both complete
    Console.WriteLine("upload and processing are done");
}
public async Task DoMultipleWork() {
var uploadTask = UploadAsync(file);
var processingTask = Task.Run( () => DoCpuWork() );

uploadTask.ContinueWith((Task t) => Console.WriteLine("YOUR_MESSAGE"), TaskContinuationOptions.OnlyOnRanToCompletion);

processingTask.ContinueWith((Task t) => Console.WriteLine("YOUR_MESSAGE"), TaskContinuationOptions.OnlyOnRanToCompletion);

await Task.WhenAll(new []{uploadTask, processingTask});

}

正如我在我的博客中所描述的那样,ContinueWith is dangerous unless you explicitly pass a scheduler. You should use await instead of ContinueWith in ~99% of cases (more detail in another blog post)。

你的情况:

private async Task UploadAsync(string filepath)
{
  var result = await fileManager.UploadAsync(filepath);
  Console.WriteLine($"Result from uploading file {result}");
}

private async Task ProcessAsync(string filepath, IProgress<T> progress)
{
  await Task.Run(() => wordProcessor.Process(filepath, progress));
  Console.WriteLine("processing completed");
}

...

await Task.WhenAll(UploadAsync(filepath), ProcessAsync(filepath, processingProgress));