代码之家  ›  专栏  ›  技术社区  ›  jonathanpeppers

.NET 4.0中的并行功能

  •  12
  • jonathanpeppers  · 技术社区  · 15 年前

    我已经介绍了.NET 4.0中一些新的并行功能的实用性。

    假设我有这样的代码:

    foreach (var item in myEnumerable)
        myDatabase.Insert(item.ConvertToDatabase());
    

    假设mydatabase.insert正在执行一些插入到SQL数据库的工作。

    理论上你可以写:

    Parallel.ForEach(myEnumerable, item => myDatabase.Insert(item.ConvertToDatabase()));
    

    自动获得利用多个核心的代码。

    但是,如果myEnumeratable只能与单个线程交互呢?并行类将由单个线程枚举并只将结果分派给循环中的工作线程吗?

    如果mydatabase只能通过单个线程进行交互怎么办?在循环的每次迭代中建立数据库连接当然不会更好。

    最后,如果我的“var项”恰好是一个用户控件或必须在UI线程上与之交互的某个对象,该怎么办?

    我应该遵循什么设计模式来解决这些问题?

    在我看来,切换到parallel/plinq/etc并不是一件容易的事情,当你处理现实世界中的应用程序时。

    5 回复  |  直到 15 年前
        1
  •  12
  •   Alex Bagnolini    15 年前

    这个 IEnumerable<T> 接口本质上不是线程安全的。 Parallel.ForEach 将自动处理此问题,并且只并行处理从枚举中出来的项。(顺序将始终按顺序遍历一个元素,但结果对象将并行化。)

    如果您的类(即T)不能由多个线程处理,那么您不应该尝试并行化这个例程。并不是每个序列都是并行化的候选者——这也是编译器不能自动完成这项工作的原因之一;)

    如果您所做的工作需要使用UI线程,那么这仍然是可能的。但是,在任何时候处理后台线程上的用户界面元素时,您都需要同样小心,并将数据封送回UI线程。在许多情况下,使用新的 TaskScheduler.FromCurrentSynchronizationContext 应用程序编程接口。我写了关于 this scenario on my blog here .

        2
  •  6
  •   LBushkin    15 年前

    所有这些都是合法的问题——PLINQ/TPL不会试图解决这些问题。 作为开发人员,编写并行化时可以正常工作的代码仍然是您的工作。编译器/tpl/plinq无法将不安全的多线程代码转换为线程安全代码…你必须确保你这样做。

    对于您描述的某些情况,您应该首先决定并行化是否明智。 如果瓶颈是获取到数据库的连接或确保正确的操作顺序,那么多线程可能不合适。

    在TPL如何将可枚举的流传输到多个线程的情况下,您的假设是正确的。 序列在单个线程上枚举,然后(可能)将每个工作项发送到单独的线程以进行操作。 这个 IEnumerable<T> 接口本身就是 threasafe,但tpl会在幕后为您处理这个问题。

    plinq/tpl帮助您做的是管理何时以及如何将工作分派给多个线程。 TPL检测机器上何时有多个内核,并自动缩放用于处理数据的线程数。如果一台机器只有一个CPU/核心,那么TPL可以选择 不平行化 这项工作。开发人员对您的好处是不必编写两个不同的路径——一个用于并行逻辑,一个用于顺序逻辑。但是,您仍有责任确保代码可以从多个线程同时安全地访问。

    我应该遵循什么样的设计模式 解决这些问题?

    这个问题没有人回答…然而,一般的做法是 immutability 在对象设计中。不变性使跨多个线程使用对象更安全,并且是使操作可并行化的最常见做法之一。事实上,像f这样的语言广泛地利用不可变性,使语言能够帮助简化并发编程。

    如果你在.NET 4.0上,你也应该研究 ConcurrentXXX 中的集合类 System.Collections.Concurrent . 在这里,您将发现一些无锁的、细粒度的锁集合构造,这些构造使编写多线程代码更加容易。

        3
  •  2
  •   Robert Harvey    15 年前

    正如你所猜测的,利用 Parallel.For Parallel.ForEach 要求您能够将工作组合成离散的单元(通过传递给 并行循环 )可以执行的 独立地。

        4
  •  0
  •   Community CDub    8 年前

    在回答和评论中有一个很好的讨论: Parallel.For(): Update variable outside of loop .

    答案是 :并行扩展不适合您。多线程问题仍然存在。这是一个很好的语法糖,但不是万能药。

        5
  •  0
  •   Mitchel Sellers    15 年前

    这是一个很好的问题,答案不是100%清楚/简洁。我会指给你一点微软的参考资料,它列出了一个很好的细节 WHEN you should use the parallel items .