假设我有一个任务列表,我想并行运行它们。但我不需要所有的人都完成才能继续,我可以只做一个。以下代码等待所有任务完成以继续。有没有办法让我在等待其他人完成的同时单独继续完成的任务?
List<string>[] x = await Task.WhenAll(new Task<List<string>>[] { task1, task2 })
// When task1 finishes, I want to process the result immediately
// instead of waiting on task2.
提前致谢!
您可能正在寻找Task.WhenAny.
我已经用它来启动一堆任务,然后在它们准备就绪时处理它们中的每一个,但我想你也可以等待一个完成并在没有循环的情况下继续,如果你不关心处理剩下的。
while(tasks.Count() > 0)
{
var task = await Task.WhenAny(tasks);
tasks.Remove(task);
var taskresult = await task;
// process result
}
如果您使用的是 C# 8 和 .NET Core,您可以利用
IAsyncEnumerable
从消费端隐藏这种复杂性。
就像这样:
static async Task Main(string[] args)
{
await foreach (var data in GetData())
{
Console.WriteLine(data);
}
Console.ReadLine();
}
static async IAsyncEnumerable<string> GetData()
{
List<Task<string>> tasks = new List<Task<string>> {GetData1(), GetData3(), GetData2()};
while (tasks.Any())
{
var finishedTask = await Task.WhenAny(tasks);
tasks.Remove(finishedTask);
yield return await finishedTask;
}
}
static async Task<string> GetData1()
{
await Task.Delay(5000);
return "Data1";
}
static async Task<string> GetData2()
{
await Task.Delay(3000);
return "Data2";
}
static async Task<string> GetData3()
{
await Task.Delay(2000);
return "Data3";
}
您可以使用 Task.WhenAny 代替。
var client = new HttpClient();
string results = await await Task.WhenAny(
client.GetStringAsync("http://example.com"),
client.GetStringAsync("http://microsoft.com"));
// results contains the HTML for whichever website responded first.
您绝对可以跟踪其他任务:
// supposing you have a list of Tasks in `myTasks`:
while( myTasks.Count > 0 )
{
var finishedTask = await Task.WhenAny(myTasks);
myTasks.Remove(finishedTask);
handleFinishedTask(finishedTask); // assuming this is a method that
// does the work on finished tasks.
}
你唯一需要注意的是:
返回的任务将始终以 RanToCompletion 状态结束,其 Result 设置为第一个要完成的任务。 即使要完成的第一个任务以已取消或故障状态结束也是如此。
WhenAny Doks中的备注(我强调)
OrderByCompletion
扩展方法在 Stephen Cleary 的 Nito.AsyncEx 库中执行此操作,签名如下:
// Creates a new collection of tasks that complete in order.
public static List<Task<T>> OrderByCompletion<T>(this IEnumerable<Task<T>> @this);
用法示例:
Task<string>[] tasks = new[] { task1, task2, task3, task4 };
foreach (var task in tasks.OrderByCompletion())
{
string result = await task;
// Do something with result
}
如果您不喜欢外部依赖项,源代码在这里.
根据Peter Csala的回答,这里是
IAsyncEnumerable
的扩展方法:
public static async IAsyncEnumerable<T> OrderedByCompletion<T>(this IEnumerable<Task<T>> tasks)
{
List<Task<T>> taskList = new List<Task<T>>(tasks);
while (taskList.Count > 0)
{
var finishedTask = await Task.WhenAny(taskList);
taskList.Remove(finishedTask);
yield return await finishedTask;
}
}