this の質問をしたところ、並列処理が必ずしも良いとは限らないことに気づきました。
これまでのところ、並列処理(c#の下)は
既存のアプリケーションと新しいアプリケーションをより高速に動作させたいので、並列処理の内部を調べていますが、今では特効薬ではないことがわかりました。
いつ使用すべきですか?ベストプラクティスはありますか?ほとんどの場合それは時間の無駄ですか?特定の種類のアプリケーションに適していますか?
この問題についてのあなたの洞察を楽しみにしています。
確実な特効薬ではありませんが、.Net 4の Task Parallel Library を使用すると、コードの並列化のいくつかの側面を簡略化できます。
あなたの質問に答えるために、問題が並列化されることでどれだけの利益が得られるかという点で、問題のタイプには確かに違いがあります。一部の問題は 恥ずかしいほど並列 と呼ばれ、その定義はタスク間で必要な通信量に大きく関係しています。
一般に並列化から大きなメリットを得るタスクのタイプに関する一連のガイドラインを思いつくと思いますが(たとえば、一部のリンカーロの回答を参照)、問題を分析して判断を下すこともできます(あなたが概念をかなり低いレベルで理解します)。
このすべてを述べたとしても、単純さとコードの読みやすさについては言うべきことがたくさんあります。一般に、並列処理のメリットが大きい問題や、パフォーマンスが優先される場合を除き、すべてを並列化しようとすると、事態が複雑になり、問題が発生します。ほとんどの場合、予備の頭脳を過ごすのに適した場所があります:)
並列処理を使用する必要がある場合がいくつかありますが、最も単純なケースは、バックグラウンドで大きなタスクを実行して、応答性の高いGUIを維持することです。これはタスクの並列処理です。もう1つのケースは、ビデオのデコード、最適化の問題の解決など、大量のデータを処理する必要がある場合です。このようなタイプの並列処理は、データ並列処理と呼ばれます。データ並列処理の場合、データのすべてのチャンクが独立して処理されるため、タスクがより速く処理されます。ただし、タスクの並列処理では、パフォーマンスが主な目的であるとは限りません。多くの場合、使いやすさを向上させるためにそれを使用する必要があります。
私たちがプラットフォームアプリケーションについて話していると仮定すると、アプリケーションが(gnatの推奨する資料に従って)複雑になるにつれて、何らかの形の並列処理が常に必要になると思います。ロードするファイルが常に大きいか、Webサービスの依存関係が遅すぎるという顧客からの苦情が常にあります。
ただし、マルチスレッド化は難しい;ため、バニラスレッドと基本的な同期プリミティブの使用には注意してください。代わりに、より高いレベルのプリミティブ、パターン、およびコンポーネントを使用してみてください(System.Threading.TasksおよびSystem.Collections.Concurrent名前空間には、多くの優れた機能があります)。さらに重要なことは、ソリューションの複雑さが増すにつれて巧妙なトリックを回避することです。
具体的には、C#のフレンドリーな近隣プラットフォームアプリケーションには、a)UIのロックを防止するため、またはb)複数の論理CPUを活用するために、UIメッセージポンプとバックグラウンドで実行されるものがある可能性があります。 「バックグラウンドで重いものを並列化する方法」に関する適切な決定リストは次のようになります。
タスクが単にCPUを集中的に使用しないが、待機に多くの時間を費やす可能性がある場合(IOまたは他のタスクの場合)、それをスレッドプールに送信します。ここでの良いパターンは待機させる可能性のある呼び出しだけをTPに送信します-フレームワークにはそのための何かがすでにあります。Begin*/End *メソッドがあり、ここで長時間待機し、安全なコンテキストにマーシャリングします(例: UIスレッド)が完了したら、並列処理の問題にさらされる可能性は低く、次のバージョンの.NETでは非同期と待機で途方もなく低くなるはずです。
細分性の低い不均一なタスク-通常はタスクの並列処理です。コマンド/タスクの設計パターンはあなたの味方です。また、 関数型プログラミング から借りてみてください-可変データと共有データを避け、継続を使用して-フレームワークを使用してください(具体的には [〜#〜] tpl [〜#〜] 、または少なくともプロデューサー/コンシューマーを実装するBlockingCollection);
粒度の高い均一なタスク-通常はデータの並列処理であり、展開するデータ構造とアルゴリズムがすべての違いを生み出します。このプロファイルでの作業単位を残りのロジックから分離し、純粋に機能することを検討してください。良いヒントとして map-reduce を使用してください。
すべてのタスクが同じように作成されていません。一部のタスクは自然に並列処理に役立ちます。たとえば、カヤックのような旅行サイトを作成しているとします。最も重要なことの1つは、ブリティッシュエアウェイズ、シンガポールエアウェイズなどの検索プロバイダーが提供するAPIを使用することです。異なるAPIに異なるスレッドを設定して、フェッチを並行して実行できるようにします。時間内に結果を返し、それを中止します(多分)。ご想像のとおり、同時実行を使用せずにこのタスクを実行することは非常に困難です。
最近、複数のコアを搭載したプロセッサーが登場し、並行プログラミングの重要性が高まっています。
私は自分の指先で8つのコアを使用しているサーバー側のアプリケーションで使用します。これは、アプリケーションのビッグデータセットでの処理速度の大幅な向上です。
それでも、並列化できる操作があることがわかっている場合にのみ使用します。データベースへのヒット(接続プールからの異なる接続を使用)、Webサービスへの要求、ディスクIO(これは議論の余地がありますが、私は、スレッドがIOソートされ、他のスレッドが作業を行うのを待つ必要がない)とすぐに作業が開始されるという仮定に基づいています。
これらはすべてわずかな改善につながりますが、これらの条件では、大規模なデータセットではシリアルよりもパラレルが優先されます。
それでも、並列操作を実行するコードを書くのはplinqを使用しても簡単ではない可能性があるため、ユーザー操作が遅い操作の影響を受ける場合のみです。
並列処理は非常に重要なツールですが、よく理解するには、こつこつになるまで何度も使用する必要があります。 TPLは私が今まで見た中で最大のライブラリであり、LINQと組み合わせたメソッド拡張機能と組み合わせることができるので、C#を使用して幸運です。
具体的に質問に答えます。
基本的にTPLを使用する理由は2つあります。
TPLは両方のシナリオで大いに役立ちます(C#5.0には、非同期プログラミングを子供向けのものにする新しい特別なトリックがいくつかあります)。
はい、あります。たとえば、Windowsフォームの場合、BackgroundWorkerを使用できます。BackgroundWorkerは、独自のスレッド外のUIオブジェクトを呼び出すことができないという事実に対処するのに役立ちます。
他にもたくさんありますが、実際に何をしているか(ASP.NET、WPF、Silverlight、WinFormsなど)によって異なります。ほとんどの場合、MSDNとStackOverflowを使用しますが、TPLを一般的に使用すればするほど、より多くの知識が得られ、それを使いやすくなり、並列処理が適切なソリューションであるかどうかがわかります。
この質問に対する普遍的な答えはありません。すべてのプロジェクトを展望して分析する必要があります。確かに、並列処理により適した特定のタイプのアプリケーションがあります。並列処理の例:
バックグラウンド処理では、UIがあり、数秒以上かかるタスクを管理するあらゆる種類のアプリケーション。 C#5.0 asyncに関する優れた記事は次の場所にあります。
http://blogs.msdn.com/b/ericlippert/archive/tags/async/
モバイルプラットフォームはデスクトップと同じレベルの処理能力を備えておらず、ユーザーがアプリを実行するときの忍耐力は通常非常に短いため、モバイルアプリケーションはこの話題に再び注目を集めています。バックグラウンド処理がアプリケーションの高速な印象を生み出す方法については、この記事を参照してください。
http://speakerdeck.com/u/mikeyk/p/secrets-to-lightning-fast-mobile-design?slide=82
学習したい場合、自分の結果(良いか悪いか)が表示されるまで、何度も何度も試してみるのに勝るものはありません。
マルチスレッドによる1つのプロセス内での並行プログラミングと並列処理は非常に強力ですが、共有データに関するすべての問題(デッドロック、更新の喪失など)が原因で、正しく実行するのも複雑です.
ただし、非常に役立つ(または必要な)場合がある状況もあります。
2に関しては、このアプローチは、データのストリームを変換するさまざまな(仮想)プロセッサが存在するワークフローの実装に非常に効果的であると思います。プロセッサは、ある種のパイプ(例:プロセッサAの出力データストリームは、プロセッサBの入力ストリームです。
この場合、同時実行性を管理するためのすべての努力は、データストリームクラス(Push_front()、pop_back()などのメソッドを持つある種のスレッドセーフキュー)の実装にローカライズできます。データのすべての管理をカプセル化できます。このキュークラスの実装の同時実行性。次に、各ワークフローノードを、システムで実行されている唯一のスレッドであるかのようにプログラムします。
同様の、しかしより一般的なアイデアに従って、俳優モデルを見るのは興味深いかもしれません。このモデルでは、各スレッドをメッセージを送受信するオブジェクトと見なしているため、スレッドを直接処理する必要はありません。標準のアクターサポートを含む言語は Erlang および Scala です。それ以外の場合は、このための適切なライブラリが必要です。 akka (Scala、Java)、 Theron (C++)。 C#でのアクターモデルの実装については、 この質問 への回答を参照してください。
結論として、スレッドは非常に便利ですが、重要な方法でスレッドを使用する場合は、いくつかのライブラリを使用してより抽象的な方法を使用することをお勧めします。