【问题标题】:Concurrent execution of async methods异步方法的并发执行
【发布时间】:2014-04-02 18:24:31
【问题描述】:

使用 async/await 模型,我有一个方法可以对 Web 服务进行 3 次不同的调用,然后返回结果的联合。

var result1 = await myService.GetData(source1);
var result2 = await myService.GetData(source2);
var result3 = await myService.GetData(source3);

allResults = Union(result1, result2, result3);

使用典型的等待,这 3 个调用将彼此同步执行。我将如何让它们同时执行并在它们完成时加入结果?

【问题讨论】:

标签: c# async-await


【解决方案1】:

我将如何让它们并行执行并在它们完成时加入结果?

最简单的方法就是创建所有任务然后等待它们:

var task1 = myService.GetData(source1);
var task2 = myService.GetData(source2);
var task3 = myService.GetData(source3);

// Now everything's started, we can await them
var result1 = await task1;
var result1 = await task2;
var result1 = await task3;

您也可以考虑Task.WhenAll。您需要考虑多个任务失败的可能性......使用上面的代码,您不会观察到 task3 的失败,例如,如果 task2 失败 - 因为您的异步方法将从 @ 传播异常987654326@ 等待之前task3

我不是在这里建议特定的策略,因为这取决于您的具体情况。您可能只关心成功/失败并记录一个失败的原因,在这种情况下,上面的代码很好。否则,您可能会将延续附加到原始任务以记录所有异常,例如。

【讨论】:

  • 谢谢乔恩。我刚遇到WhenAll。我会考虑使用它。顺便说一句,我假设在代码示例中您打算从方法调用中删除等待,对吗?
  • 如果你awaitTask.WhenAll(常见情况),它不会抛出AggregateException。相反,它会(重新)抛出 一个 来自错误任务的异常。
【解决方案2】:

作为更通用的解决方案,您可以使用我在下面编写的 api,它还允许您定义最大并发异步请求数的实时限制机制。

inputEnumerable 将是您的源的可枚举,而 asyncProcessor 是您的异步​​委托(在您的示例中为 myservice.GetData)。

如果 asyncProcessor - myservice.GetData - 返回 void 或只是一个没有任何类型的任务,那么您可以简单地更新 api 以反映这一点。 (只需替换所有 Task 对 Task 的引用)

    public static async Task<TOut[]> ForEachAsync<TIn, TOut>(
        IEnumerable<TIn> inputEnumerable,
        Func<TIn, Task<TOut>> asyncProcessor,
        int? maxDegreeOfParallelism = null)
    {
        IEnumerable<Task<TOut>> tasks;

        if (maxDegreeOfParallelism != null)
        {
            SemaphoreSlim throttler = new SemaphoreSlim(maxDegreeOfParallelism.Value, maxDegreeOfParallelism.Value);

            tasks = inputEnumerable.Select(
                async input =>
                    {
                        await throttler.WaitAsync();
                        try
                        {
                            return await asyncProcessor(input).ConfigureAwait(false);
                        }
                        finally
                        {
                            throttler.Release();
                        }
                    });
        }
        else
        {
            tasks = inputEnumerable.Select(asyncProcessor);
        }

        await Task.WhenAll(tasks);
    }

【讨论】:

    【解决方案3】:

    您可以使用 Parallel 类:

    Parallel.Invoke(
    () => result1 = myService.GetData(source1),
    () => result2 = myService.GetData(source2),
    () => result3 = myService.GetData(source3)
    );
    

    欲了解更多信息,请访问:http://msdn.microsoft.com/en-us/library/system.threading.tasks.parallel(v=vs.110).aspx

    【讨论】:

    • 这没有用,GetData 是一个异步方法,所以并行调用它没有任何意义。
    猜你喜欢
    • 2020-10-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-12-02
    • 2018-07-26
    相关资源
    最近更新 更多