等待IEnumerable <task <t>&gt;单独C#

时间:2015-09-24 12:51:51

标签: winforms c#-4.0 async-await task

简而言之,我有一个可枚举的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()是阻塞的,因此也是不受欢迎的。

修改:所有任务应同时启动。然后他们可以按任何顺序完成。

3 个答案:

答案 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();
}