PLINQ(Parallel Linq)是一种编写常规Linq查询的新方法,以便并行运行-换句话说,框架将自动处理跨多个线程运行查询,从而使它们更快地完成(即使用多个CPU核心)。
例如,假设您有一堆字符串,您想获取所有以字母"A"开头的字符串。您可以像这样编写查询:
var words = new[] { "Apple", "Banana", "Coconut", "Anvil" };
var myWords = words.Select(s => s.StartsWith("A"));
这很好用。但是,如果您要搜索50000个单词,您可能需要利用每个测试是独立的事实,并将其分配到多个核心上:
var myWords = words.AsParallel().Select(s => s.StartsWith("A"));
这就是将普通查询转化为运行在多个核心上的并行查询所需要做的一切,非常不错。
TPL(任务并行库)可以看作是 PLINQ 的补充,它们一起组成了 Parallel Extensions。虽然 PLINQ 大部分基于无副作用的函数式编程,但正是 TPL 用来处理副作用。如果你想实际并行执行工作,而不仅仅是并行搜索/选择内容,则需要使用 TPL。
TPL 实际上就是暴露了 For
, Foreach
, 和 Invoke
的 Parallel
类。像 Invoke
就有点像在 ThreadPool
中排队任务,但使用起来更简单。在我看来,更有趣的是 For
和 Foreach
部分。例如,假设你有一堆文件要压缩,你可以编写常规的顺序版本:
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核心,并可能在一半或四分之一的时间内完成。
与仅将所有内容扔到
ThreadPool
中相比,这种方法的优势在于它实际上是同步运行的。如果使用
ThreadPool
(或只是普通的
Thread
实例),您必须想出一种找出所有任务何时完成的方法,虽然这并不是非常复杂,但很多人往往会弄错或至少有困难。使用
Parallel
类时,您不必考虑这些; 多线程方面对您隐藏了,所有这些都在幕后处理。
响应式扩展(Rx)实际上是完全不同的东西。这是一种不同的事件处理方式。确实有很多关于这个的资料需要涵盖,但简而言之,与将事件处理程序连接到事件不同,Rx允许您将事件序列视为......好吧,序列(
IEnumerable<T>
)。您可以以迭代方式处理事件,而不是在随机时间异步触发它们,您必须一直保存状态才能检测特定顺序中发生的一系列事件。
我发现Rx最酷的例子之一是
这里。跳转到“ Linq to IObservable”部分,他在仅使用4行代码的情况下实现了通常在WPF中很难处理的拖放处理程序。 Rx为您提供了事件的
组合,这是您在常规事件处理程序中真正没有的内容,并且像这样的代码片段也容易重构为行为类,您可以将其套用在任何地方。
就是这样。这些是.NET 4.0中可用的一些更酷的功能。当然还有其他几个,但这些就是你问的!