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

时间:2015-03-13 02:55:21

标签: c# asynchronous async-await

想象一下以下场景:

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。

3 个答案:

答案 0 :(得分:6)

您想使用Task.WhenAny返回完成的第一个任务。然后,您可以通过与原始任务进行比较来确定已完成的任务。在返回之前,您应该等待另一个显式完成(或等待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");
}

答案 1 :(得分:2)

正如我在博客中描述的ContinueWith is dangerous unless you explicitly pass a scheduler。您应该在~99%的案例中使用await代替ContinueWithanother 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));

答案 2 :(得分:0)

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});

}