2016-09-21 24 views
5

完成假设我有以下的回调:是否有当一个任务Task.WhenAll

IEnumerable<Task<TimeSpan>> tasks = //... 
TimeSpan[] results = await Task.WhenAll(tasks); 
// Handle results 

到时候我能处理所有的任务必须完成的结果。

有没有办法按需处理每个结果

就像注册一个代表/回调当任务完成后,将得到执行:

IEnumerable<Task<TimeSpan>> tasks = //... 
await Task.WhenAll(tasks, result => 
{ 
    // A task has finished. This will get executed. 
    // result is of type TimeSpan 
}); 
+1

也许'任务[I] .ContinueWith()'? –

回答

4

有没有一种方法来处理需求每个结果?

是的,你用WhenAny,而不是WhenAll ...或者每个任务调用ContinueWith

例如,对于WhenAny方法:

ISet<Task<TimeSpan>> tasks = new HashSet<Task<TimeSpan>>(...); 
while (tasks.Count != 0) 
{ 
    var task = await Task.WhenAny(tasks); 
    // Use task here 
    tasks.Remove(task); 
} 

还有就是你改造任务的原始序列为任务的序列完成,以便另一种选择,你可以使用,但是给了相同的结果。详细信息可在this blog post,但结果是,你可以使用:

foreach (var task in tasks.InCompletionOrder()) 
{ 
    var result = await task; 
    // Use the result 
} 
+0

谢谢!我认为我要用'ContinueWith'方法,因为它看起来更清晰,更正确的语义 –

+0

@JonSkeet让我们获得一些声誉:) –

+0

@MatiasCicero:两者在语义上是正确的 - 它只取决于什么结果是最简单的。添加一个链接到另一个替代品... –

4

有没有一种方法来处理需求每个结果?

就像注册一个代表/回调当任务完成

是会得到执行,你只需要调整你的思考了一下。

忘记注册回调(ContinueWith is a dangerous, extremely low-level API)。另外,你几乎从不需要完成任务。相反,根据操作(任务)考虑您的问题。

现在,您拥有一组返回TimeSpan的任务。该集合中的每个项目都是一个返回TimeSpan的单个操作。你真正想要做的是引入一个高级操作的概念,它等待原始操作完成,然后执行你的操作后逻辑。

这正是async/await是:

private static async Task<TimeSpan> HandleResultAsync(Task<TimeSpan> operation) 
{ 
    var result = await operation; 
    // A task has finished. This will get executed. 
    // result is of type TimeSpan 
    ... 
    return result; // (assuming you want to propagate the result) 
} 

现在,你想这种更高级别的操作应用到您的现有业务。 LINQ的Select非常适合这样的:

IEnumerable<Task<TimeSpan>> tasks = ... 
IEnumerable<Task<TimeSpan>> higherLevelTasks = tasks.Select(HandleResultAsync); 

TimeSpan[] results = await Task.WhenAll(higherLevelTasks); 
// By the time you get here, all results have been handled individually. 

如果您不需要结果的最终集合,这可以进一步简化:

private static async Task HandleResultAsync(Task<TimeSpan> operation) 
{ 
    var result = await operation; 
    // A task has finished. This will get executed. 
    // result is of type TimeSpan 
    ... 
} 

IEnumerable<Task<TimeSpan>> tasks = ... 
IEnumerable<Task> higherLevelTasks = tasks.Select(HandleResultAsync); 
await Task.WhenAll(higherLevelTasks); 
+0

我真的很惊讶,因为你使用了LINQ的'Select'。这是完美的! –

相关问题