web-dev-qa-db-ja.com

Reactive Framework、PLINQ、TPL、Parallel Extensionsはどのように相互に関連していますか?

少なくとも.NET4.0のリリース以来、Microsoftは並列および非同期プログラミングのサポートに多大な努力を払ってきたようであり、これに関連する多くのAPIとライブラリが出現したようです。特に次の派手な名前は最近どこでも絶えず言及されています:

  • リアクティブフレームワーク、
  • PLINQ(Parallel LINQ)、
  • TPL(タスク並列ライブラリ)と
  • 並列拡張。

現在、これらはすべてMicrosoft製品のようであり、.NETの非同期または並列プログラミングシナリオを対象としているようです。しかし、それらのそれぞれが実際に何であるか、そしてそれらが互いにどのように関連しているかは完全には明確ではありません。いくつかは実際には同じものかもしれません。

一言で言えば、誰もが何が何であるかについて記録を立てることができますか?

66
bitbonk

[〜#〜] 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は主に機能プログラミングスタイルに基づいており、no副作用がありますが、副作用はまさにTPLの目的です。単に並行して検索/選択するのではなく、実際にdo work並行して実行したい場合は、TPLを使用します。

TPLは、本質的にはParallelクラスであり、ForForeach、およびInvokeのオーバーロードを公開します。 Invokeは、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インスタンス)、すべてのタスクがいつ終了したかを確認する方法を考え出す必要がありますが、これは終了していません。 t ひどく複雑です。これは、多くの人が失敗する傾向があるか、少なくとも問題を抱えているものです。 Parallelクラスを使用する場合、実際にそれについて考える必要はありません。マルチスレッドの側面はあなたから隠されており、すべて舞台裏で処理されます。


リアクティブエクステンション(Rx)は実際にはまったく別の獣です。これは、イベント処理についての別の考え方です。これについてカバーする資料は本当にたくさんありますが、長い話を短くするために、イベントハンドラーをイベントに接続する代わりに、Rxではイベントのシーケンスを...まあ、シーケンス(IEnumerable<T>)。イベントをランダムに非同期で発生させるのではなく、反復的に処理することができます。特定の順序で発生する一連のイベントを検出するには、常に状態を保存し続ける必要があります。

私が見つけたRxの最もクールな例の1つは、 ここ です。 「LinqtoIObservable」セクションにスキップして、ドラッグアンドドロップハンドラーを実装します。これは通常、WPFでは面倒ですが、わずか4行のコードで実行できます。 Rxは、通常のイベントハンドラーでは実際にはないイベントのcompositionを提供します。また、これらのようなコードスニペットは、どこにでも配置できる動作クラスにリファクタリングするのも簡単です。


以上です。これらは、.NET4.0で利用できるより優れた機能の一部です。もちろん、他にもいくつかありますが、これらはあなたが尋ねたものでした!

95
Aaronaught

アーロノートの答えは好きですが、RxとTPLは異なる問題を解決すると思います。 TPLチームが追加したものの一部は、スレッドプリミティブと、ThreadPoolのようなランタイムのビルディングブロックに対する大幅な機能強化です。そして、リストするものはすべて、これらのプリミティブとランタイム機能の上に構築されています。

しかし、TPLとRxは2つの異なる問題を解決します。 TPLは、プログラムまたはアルゴリズムが「プル&キューイング」の場合に最適に機能します。 Rxは、プログラムまたはアルゴリズムがストリームからのデータに「反応」する必要がある場合(マウス入力など)、またはWCFなどのエンドポイントから関連メッセージのストリームを受信する場合に優れています。

ファイルシステムのように作業したり、コレクションを反復処理したり、組織図のように階層を歩いたりするには、TPLの「作業単位」の概念が必要です。いずれの場合も、プログラマーは全体的な作業量について推論でき、作業は特定のサイズのチャンクに分割でき(タスク)、階層全体で計算を行う場合は、タスクを「チェーン」できます。 。そのため、特定の種類の作業はTPLの「タスク階層」モデルに役立ち、キャンセルなどの配管の機能強化の恩恵を受けます(CancellationTokenSourceのチャネル9ビデオを参照)。 TPLには、ほぼリアルタイムのデータ処理などの特殊なドメイン用のノブもたくさんあります。

Rxは、ほとんどの開発者が最終的に使用する必要があるものになります。これは、WPFアプリケーションが外部データ(IMクライアントへのIMメッセージのストリーム)や外部入力(Aaronaughtからリンクされたマウスドラッグの例など)などの外部メッセージに「反応」する方法です。内部では、RxはTPL/BCLのスレッドプリミティブ、TPL/BCLのスレッドセーフコレクション、およびThreadPoolなどのランタイムオブジェクトを使用します。私の考えでは、Rxはあなたの意図を表現するためのプログラミングの「最高レベル」です。

平均的な開発者が、Rxで表現できる一連の意図に頭を悩ませることができるかどうかはまだわかっていません。 :)

しかし、今後数年間は、TPLとRxが、LINQ-to-SQLとEntityFrameworkのような次の議論になると思います。同じドメインには2つの種類のAPIがあり、さまざまなシナリオに特化していますが、多くの点で重複しています。ただし、TPLとRxの場合、実際にはお互いを認識しており、アプリケーションを構成して両方のフレームワークを一緒に使用するための組み込みアダプターがあります(PLINQループからの結果をIObservable Rxストリームにフィードするなど)。並列プログラミングを行ったことがない人にとっては、スピードを上げるための学習がたくさんあります。

更新:私は過去6か月間(最初の回答から18か月間)、通常の作業でTPLとRxNetの両方を使用しています。中間層WCFサービス(エンタープライズLOBサービス)でのTPLおよび/またはRxNetの選択についての私の考え: http://yzorgsoft.blogspot.com/2011/09/middle-tier-tpl-andor-rxnet .html

30
yzorg