对多个异步调用的反应不同
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");
}
我如何更改该代码,以便无论哪个代码先结束,它都执行一些特定的(同步或异步)代码。
所以我触发了两个任务,当 taskA
或 taskB
结束时,我只是 运行 一些独立于其他代码(同步或异步)的代码。
我想也许 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));
想象一下以下场景:
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");
}
我如何更改该代码,以便无论哪个代码先结束,它都执行一些特定的(同步或异步)代码。
所以我触发了两个任务,当 taskA
或 taskB
结束时,我只是 运行 一些独立于其他代码(同步或异步)的代码。
我想也许 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));