简而言之,我有一个可枚举的Task,我想以 await 的方式运行数组中的每个Task。每个任务都将执行一个缓慢的网络操作,从我的结束,我只需要在任务完成后更新WinForm UI。
以下是我目前正在使用的代码,但我认为这更像是一个黑客而不是一个实际的解决方案:
private void btnCheckCredentials_Click(object sender, EventArgs e)
{
// GetNetCredentials() is irrelevant to the question...
List<NetworkCredential> netCredentials = GetNetCredentials();
// This call is not awaited. Displays warning!
netCredentials.ForEach(nc => AwaitTask(ValidateCredentials(nc)));
}
public async Task<bool> ValidateCredentials(NetworkCredential netCredential)
{
// Network-reliant, slow code here...
}
public async Task AwaitTask(Task<bool> task)
{
await task;
// Dumbed-down version of displaying the task results
txtResults.Text += task.Result.ToString();
}
显示第二行btnCheckCredentials_Click()警告:
由于未等待此调用,因此在完成调用之前会继续执行当前方法。考虑将'await'运算符应用于调用的结果。
这实际上是按照我想要的方式工作,因为我不想等待操作完成。相反,我只是想要解雇任务,然后在每个任务完成后立即采取行动。
Task.WhenAny()或Task.WhenAll()方法按照我的预期运行,因为我想知道每个任务完成 - 一旦完成。 Task.WaitAll()或Task.WaitAny()是阻塞的,因此也是不受欢迎的。
修改:所有任务应同时启动。然后他们可以按任何顺序完成。
答案 0 :(得分:1)
您可以使用Task.WhenAny
将其标记为async
来实现此目的(async void
此处没有问题,因为您在事件处理程序中):
private async void btnCheckCredentials_Click(object sender, EventArgs e)
{
// GetNetCredentials() is irrelevant to the question...
List<NetworkCredential> netCredentials = GetNetCredentials();
var credentialTasks = netCredentials
.Select(cred => ValidateCredentialsAsync(cred))
.ToList();
while (credentialTasks.Count > 0)
{
var finishedTask = await Task.WhenAny(credentialTasks);
// Do stuff with finished task.
credentialTasks.Remove(finishedTask);
}
}
答案 1 :(得分:1)
您可以触发并忘记每项任务,并在任务完成时添加回调。
private async void btnCheckCredentials_Click(object sender, EventArgs e)
{
List<NetworkCredential> netCredentials = GetNetCredentials();
foreach (var credential in netCredentials)
{
ValidateCredentails(credential).ContinueWith(x=> ...) {
};
}
}
因此,您可以创建回调方法,而不是labda表达式,并确切知道特定任务何时完成。
答案 2 :(得分:1)
您在寻找Task.WhenAll
吗?
await Task.WhenAll(netCredentials.Select(nc => AwaitTask(ValidateCredentials(nc)));
您可以在AwaitTask
中完成所需的所有完成处理。
await task;
有点尴尬。我这样做:
public async Task AwaitTask(netCredential credential)
{
var result = await ValidateCredentails(credential);
// Dumbed-down version of displaying the task results
txtResults.Text += result.ToString();
}