Reactive Framework,PLINQ,TPL和并行扩展如何相互关联?


68

至少自.NET 4.0发布以来,Microsoft似乎在支持并行和异步编程上付出了很多努力,并且似乎已经出现了许多与此相关的API和库。特别是最近到处都经常提到以下奇特的名字:

  • 反应框架
  • PLINQ(平行LINQ),
  • TPL(任务并行库)和
  • 并行扩展。

现在它们似乎都是Microsoft产品,它们似乎都针对.NET的异步或并行编程方案。但是,目前还不清楚它们实际上是什么以及它们之间如何相互联系。有些可能实际上是同一回事。

简而言之,任何人都可以直接确定什么是记录吗?


我已经编辑了这个问题以尝试澄清一下,然后投票决定重新打开它。就是说,我不是.NET专家,所以我可能一团糟。如果您认为我在某个地方犯了错误,可以随时对其进行进一步编辑(甚至完全还原我的更改)。另外,坦率地说,我仍然认为这个问题感觉过于宽泛和不明确的,以适应以及对堆栈溢出; 也就是说,鉴于它的确得到了高度评​​价和接受,我愿意接受它可能是一个例外。
Ilmari Karonen 2015年

我要说的是,每个知道以上4件事的人(每个可能回答这个问题的人)都将立即知道这个问题的全部含义。投票和答案证明了这一点。无论如何,我已经编辑了问题,以便尽可能清楚。
bitbonk 2015年

Answers:


97

PLINQ(Parallel Linq)只是编写常规Linq查询以使其并行运行的一种新方法-换句话说,框架将自动处理跨多个线程运行查询,以使它们更快地完成(即使用多个CPU内核) )。

例如,假设您有一堆字符串,并且想要获取所有以字母“ A”开头的字符串。您可以这样编写查询:

var words = new[] { "Apple", "Banana", "Coconut", "Anvil" };
var myWords = words.Select(s => s.StartsWith("A"));

这很好。但是,如果您要搜索50,000个单词,则可能要利用每个测试都是独立的这一事实,并将其分为多个核:

var myWords = words.AsParallel().Select(s => s.StartsWith("A"));

这就是将常规查询转换为在多个内核上运行的并行查询所要做的全部工作。很简约。


TPL(任务并行库)是排序的补充PLINQ的,和他们一起构成了并行扩展。尽管PLINQ主要基于一种没有副作用的编程功能样式,但副作用正是TPL的目的。如果您实际上想并行工作而不是并行搜索/选择事物,则可以使用TPL。

第三方物流基本上是Parallel暴露的重载类ForForeachInvokeInvoke有点像在中排队任务ThreadPool,但使用起来更简单。IMO,更有趣的位是ForForeach。例如,假设您要压缩一堆文件。您可以编写常规的顺序版本:

string[] fileNames = (...);
foreach (string fileName in fileNames)
{
    byte[] data = File.ReadAllBytes(fileName);
    byte[] compressedData = Compress(data);
    string outputFileName = Path.ChangeExtension(fileName, ".zip");
    File.WriteAllBytes(outputFileName, compressedData);
}

同样,此压缩的每次迭代完全独立于其他任何迭代。我们可以一次执行几个操作来加快速度:

Parallel.ForEach(fileNames, fileName =>
{
    byte[] data = File.ReadAllBytes(fileName);
    byte[] compressedData = Compress(data);
    string outputFileName = Path.ChangeExtension(fileName, ".zip");
    File.WriteAllBytes(outputFileName, compressedData);
});

再次,这就是并行化此操作所需的全部。现在,当我们运行我们的CompressFiles方法(或我们决定调用的任何方法)时,它将使用多个CPU内核,并且可能会在一半或1/4的时间内完成。

这样做的好处ThreadPool是,它实际上是同步运行的。如果使用ThreadPool替代Thread实例(或仅使用普通实例),则必须想出一种方法来找出所有任务的完成时间,虽然这并不十分复杂,但很多人倾向于这样做搞砸或至少有麻烦。使用Parallel该类时,您不必真正考虑它。多线程方面对您来说是隐藏的,所有这些都在后台处理。


Reactive Extensions(Rx)实际上完全是另一种野兽。这是对事件处理的另一种思考方式。Rx确实有很多内容要讲,但是总而言之,Rx不需要将事件处理程序连接到事件,而是让您将事件序列视为...序列(IEnumerable<T>)。您必须以迭代的方式处理事件,而不是让它们在随机时间异步触发,在这种情况下,您必须一直保持状态以检测按特定顺序发生的一系列事件。

我发现的Rx最酷的示例之一在这里。跳到“ Linq to IObservable”部分,在那里他仅用4行代码即可实现拖放处理程序,这通常是WPF中的难题。RX给你组成的事件,有些东西你真的没有定期事件处理程序和代码片段像这些也可以直接连接到重构行为的类,你可以随时随地在袖子。


就是这样。这些是.NET 4.0中提供的一些更酷的功能。当然还有更多,但是这些是您问的!


在.net 3.5或更低版本中是否可用?
Myster 2010年

1
@Myster:可以使用RX(msdn.microsoft.com/en-us/devlabs/ee794896.aspx)。PLINQ作为CTP可以使用很久了,但是现在不再提供-您必须为此进行升级。
Aaronaught

2
C#异步CTP附带的TPL数据流库(TDF)看起来非常好。.NET中间件应该更容易保持在并行处理的“性能最佳点”之内。为了获得最佳性能(考虑吞吐量和延迟),请设置限制。因此,每个处理“块”都可以拥有自己的“缓冲上限”,并且可以具有并行处理上限。您还可以告诉每个块处理批处理而不是单独的消息。这看起来很棒。
yzorg 2011年

30

我喜欢Aaronaught的答案,但是我想说Rx和TPL解决了不同的问题。TPL团队添加的一部分是线程原语和对运行时构建块(如ThreadPool)的显着增强。您列出的所有内容都基于这些原语和运行时功能。

但是TPL和Rx解决了两个不同的问题。当程序或算法为“拉入和排队”时,TPL效果最佳。当程序或算法需要对流中的数据进行“反应”时(例如鼠标输入或从端点(如WCF)接收相关消息流)时,Rx表现出色。

您需要TPL中的“工作单元”概念来完成文件系统之类的工作,遍历集合或遍历组织结构图之类的层次结构。在每种情况下,程序员都可以推断出全部工作量,可以将工作分解为一定大小的块(任务),并且在按层次结构进行计算的情况下,可以将任务“链接”在一起。因此,某些类型的工作适用于TPL“任务层次”模型,并受益于诸如取消之类的管道功能的增强(请参见CancellationTokenSource上的Channel 9视频)。TPL还具有许多专门领域的旋钮,例如近实时数据处理。

Rx将是大多数开发人员最终应该使用的东西。这就是WPF应用程序如何对外部消息(例如外部数据(IM消息流到IM客户端的流)或外部输入(例如从Aaronaught链接的鼠标拖动示例))进行“反应”的方式。在幕后,Rx使用来自TPL / BCL的线程原语,来自TPL / BCL的线程安全集合以及运行时对象(如ThreadPool)。在我看来,Rx是表达您意图的最高级编程。

普通开发人员是否可以围绕Rx可以表达的意图集中注意力。:)

但是我认为,在接下来的几年中,TPL与Rx的争夺将成为LINQ-to-SQL与Entity Framework之类的下一场辩论。在同一域中有两种API,它们专用于不同的场景,但是在很多方面都有重叠。但是在TPL和Rx的情况下,它们实际上彼此了解,并且内置了适配器来组合应用程序并一起使用这两个框架(例如将结果从PLINQ循环馈送到IObservable Rx流中)。对于尚未进行任何并行编程的人们,需要大量学习以加快速度。

更新:在过去的6个月中(自原始回答以来的18个月中),我在日常工作中一直使用TPL和RxNet。我TPL的选择的思想和/或RxNet在中间层WCF服务(企业LOB服务): http://yzorgsoft.blogspot.com/2011/09/middle-tier-tpl-andor-rxnet.html


1
要注意的另一件事是,TPL和TPL数据流首先假设您要并行处理。默认情况下,Rx以“丰富事件”开始,因此它使您跳了圈来进行并行处理(例如增加并行处理的并行项的数量)。请参阅“将IObservable视为线程安全的思想”“如何使用Rx异步处理队列”。我认为这也太容易了以至于意外地在Rx中使用了阻塞操作
yzorg 2013年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.