【问题标题】:What would be a better way of using task parallel library使用任务并行库的更好方法是什么
【发布时间】:2012-07-08 10:14:18
【问题描述】:

我刚开始使用 TPL,我想同时调用多个 Web 服务。据我所知,我看到了两种方法。

Parallel.ForEach:

List<ServiceMemberBase> list = new List<ServiceMemberBase>(); //Take list from somewhere.
        Parallel.ForEach(list, member =>
            {
                var result = Proxy.Invoke(member);
                //...
                //Do stuff with the result
                //...
            });

Task&lt;T&gt;:

List<ServiceMemberBase> list = new List<ServiceMemberBase>(); //Take list from somewhere.
        ForEach(var member in list)
        {
            Task<MemberResult>.Factory.StartNew(() => proxy.Invoke(member));
        }

        //Wait for all tasks to finish.
        //Process the result objects.

不管语法是否正确,这些是否等同?

它们会产生相同的结果吗?如果不是,为什么?哪个更可取?

【问题讨论】:

    标签: c# .net task-parallel-library parallel.foreach


    【解决方案1】:

    对于您讨论的代码和用例,这两种方法本质上是等效的。

    当您必须将输入范围划分为多个任务(此处不适用)时,Parallel.ForEach 很有用,或者更容易同步合并多个独立并行操作的结果(可能适用于此?)。

    无论如何,您已经正确地注意到,在 Parallel.ForEach 案例中,您不必手动同步等待完成,而如果您手动启动任务,则必须自己管理该同步。在这种情况下,您可能会使用 Task.WaitAll(...) 之类的东西。

    【讨论】:

    • 感谢您的回复。我最终使用了 Parallel.ForEach,我们看到我们的生产(16 核机器)的响应时间提高了大约 25%。我猜大部分收益是在并行数据处理中,而不是在对 Web 服务本身的并行调用中。
    【解决方案2】:

    在两段代码之间,Parallel.ForEach() 会更高效,因为它在一个 Task 中处理多个项目,一个接一个。

    但是他们都将使用ThreadPool 允许的线程数,在这种情况下这不是一个好主意。这是因为ThreadPool 擅长猜测最佳线程数,如果你有非常短的、受 CPU 限制的Tasks,这与这里的情况相去甚远。

    因此,我认为最好的选择是将并行度手动限制为一个小数字(您必须测量以找出哪个数字给出了最佳结果):

    List<ServiceMemberBase> list = …; //Take list from somewhere.
    Parallel.ForEach(list, new ParallelOptions { MaxDegreeOfParallelism = 10 },
    member =>
    {
        var result = Proxy.Invoke(member);
        //...
        //Do stuff with the result
        //...
    });
    

    如果您可以异步执行 Web 服务调用,效率会更高。这样做并同时限制并行度并不是很容易,除非您使用的是 C# 5。如果您使用的是 C# 5 并且还更新了 Proxy 以支持基于任务的异步模式 (TAP) ,您可以使用 TPL 数据流更有效地执行您的代码:

    var actionBlock = new ActionBlock<ServiceMemberBase>(
        async member =>
        {
            var result = await Proxy.InvokeAsync(member);
            //...
            //Do stuff with the result
            //...
        }
        new ExecutionDataflowBlockOptions { MaxDegreeOfParallelism = 10 });
    

    【讨论】:

      【解决方案3】:

      如果不考虑或查看输出,我无法确定两者是否相同;但是我怀疑它们是否有那么大的不同。关于哪个更好的问题是主观的,具体取决于场景。回答哪个更可取也是非常主观的,在您提供的场景中,我会说我更喜欢 Parallel.ForEach 因为我可以阅读它,但是如果您的开发团队不习惯 Parallel 库那么第二个版本就可以了。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-10-30
        • 2014-05-03
        • 1970-01-01
        • 1970-01-01
        • 2012-06-12
        • 2013-04-15
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多