web-dev-qa-db-ja.com

並行性:どのように設計に取り組み、実装をデバッグしますか?

私は数年前から並行システムを開発しており、正式なトレーニングが不足している(学位がない)にもかかわらず、このテーマについてはかなりよく理解しています。 ErlangやGoなど、同時実行を容易にするために設計された、最近話題になっているいくつかの新しい言語があります。同時実行性に対する彼らのアプローチは、システムをスケーラブルにし、複数のコア/プロセッサー/マシンを利用する方法についての私自身の経験を反映しているようです。

ただし、目的を視覚化するのに役立つツールは非常に少なく、少なくとも元のビジョンに近いことを確認します。並行コードのデバッグは、並行処理用に設計されていない言語(C/C++、C#、Javaなど)では悪夢になる可能性があります。特に、開発環境の1つのシステムですぐに発生する状態を再現することはほぼ不可能です。

では、並行性と並列処理を処理するシステムを設計するためのアプローチは何ですか?例:

  • 並行にすることができるものと順次にする必要があるものをどのように区別しますか?
  • どのようにしてエラー状態を再現し、アプリケーションの実行中に何が起こっているのかを確認しますか?
  • アプリケーションの同時並行部分間の相互作用をどのように視覚化しますか?

これらのいくつかについては私自身の回答がありますが、もう少し学びたいと思います。

編集

これまでのところ、良いインプットがたくさんあります。リンクされている記事の多くは非常に優れており、それらのいくつかはすでに読んだことがあります。

並行プログラミングに関する個人的な経験から、シーケンシャルプログラミングとは異なる考え方が必要だと思いました。精神的な格差は、おそらくオブジェクト指向プログラミングと手続き型プログラミングの違いと同じくらい広いです。この一連の質問では、体系的に回答にアプローチするために必要な思考プロセス(つまり理論)にさらに焦点を当てたいと思います。より具体的な答えを提供するとき、例を提供することは役立ちます-あなたが個人的に経験したもの。

バウンティの目標

何をすべきか教えてはいけません。私はすでにそれを制御しています。あなたが何をしているのか教えてください。 あなたがこれらの問題をどのように解決するか教えてください。

37
Berin Loritsch

私は数年前から並行システムを開発しており、正式なトレーニングが不足している(つまり学位がない)にもかかわらず、この問題についてはかなりよく理解しています。

私が知っている最高のプログラマーの多くは大学を卒業していません。私は哲学を学びました。

C/C++、C#、Javaなど)。特に、開発環境の1つのシステムですぐに発生する状態を再現することはほぼ不可能です。

はい

並行にすることができるものと順次にする必要があるものをどのように区別しますか?

私たちは通常、1000マイルの高さの比喩から始めて、自分自身(最初に)と他の人(2番目)にアーキテクチャを明確にします。

その問題に直面したとき、私たちは常に、並行オブジェクトの可視性を非並行オブジェクトに制限する方法を見つけました。

最近、scalaでActorsを発見しました。古いソリューションは一種の「ミニアクタ」であり、scalaのものよりもはるかに強力ではありません。そこから始めましょう。

もう1つの提案は、できるだけ多くの問題をスキップすることです。たとえば、メモリにマップを保持する代わりに集中型キャッシュ(テラコッタ)を使用する、同期メソッドではなく内部クラスコールバックを使用する、共有メモリに書き込む代わりにメッセージを送信するなどです。

scalaを使用すると、とにかくすべてがはるかに簡単になります。

どのようにしてエラー状態を再現し、アプリケーションの実行中に何が起こっているのかを確認しますか?

ここでは本当の答えはありません。同時実行性のユニットテストと、アプリケーションにできるだけストレスをかける負荷テストスイートがあります。

アプリケーションの同時並行部分間の相互作用をどのように視覚化しますか?

ここでも本当の答えはありません。私たちはメタファーをホワイトボードに設計し、建築面で競合がないことを確認しようとしています。

ここでのアーチとは、ニールフォードの定義を意味します。Swアーキテクチャは、後で変更するのが非常に難しいすべてのものです。

プログラミングのせいで、シーケンシャルプログラミングとは異なる考え方が必要だと思います。

たぶん私にとっては、並行して考えることは単に不可能なので、並行して考える必要がないようにソフトウェアを設計し、並行レーン間のクラッシュを回避するために明確なガードレールを備えたソフトウェアを設計します。

11
Uberto

私にとってはすべてのデータです。データを正しく分割すると、並列処理が簡単になります。保持、デッドロックなどの問題はすべて解消されます。

これが並列化する唯一の方法ではないことは知っていますが、私にとっては最も便利です。

説明するには、(それほど速くない)ストーリー:

2007年から2009年にかけて大規模な財務(株式市場管理)システムに取り組みましたが、データの処理量は非常に多かったです。たとえば、クライアントの1つのアカウントに対して実行されたすべての計算には、平均的なワークステーションで約1〜3秒かかり、30k以上のアカウントがありました。毎晩、システムを閉じることはユーザーにとって大きな苦痛でした(通常、エラーマージンなしで処理に6時間以上かかりました)。

問題をさらに調査すると、複数のコンピュータ間で計算を並列化できることがわかりましたが、それでも古いデータベースサーバー(SQL 6.5をエミュレートするSQL 2000サーバー)に大きなボトルネックが残ることになります。

最小処理パケットが単一のアカウントの計算であることはかなり明らかであり、主なボトルネックはデータベースサーバーの保持でした( "sp_who"で、同じ処理を待機している複数の接続を確認できます)。したがって、並列処理は次のようになります。

1)1つの単一のプロデューサー。データベースの読み取りまたはデータベースへの書き込みを順番に行います。ここでは同時実行は許可されていません。プロデューサーは、コンシューマーのためにジョブのキューを準備しました。データベースはこのプロデューサーにのみ属していました。

2)複数のマシン上の複数の消費者。コンシューマのそれぞれが、計算の準備ができているキューからデータのパケット全体を受信しました。各deqeue操作は同期されます。

3)計算後、各コンシューマはデータを永続化するために、データをインメモリ同期キューにプロデューサに送り返しました。

いくつかのチェックポイント、トランザクションが正しく保存されたことを保証するためのメカニズムがいくつかありました(取り残されたものはありません)が、作業全体はその価値がありました。最終的に、10台のコンピューター(およびプロデューサー/キューコンピューター)に分散された計算により、システム全体の終了時間が15分に短縮されました。

SQL 6.5の並行性管理が不十分なために発生する保持の問題を取り除くだけで、大きなメリットが得られました。残りはほぼ直線的で、「グリッド」に追加された新しいコンピューターごとに、データベースでのシーケンシャルな読み取り/書き込み操作の「最大効率」に達するまで、処理時間が短縮されました。

6
Machado

マルチスレッド環境での作業は難しく、コーディング規律が必要です。ロックの取得、ロックの解除、グローバル変数へのアクセスなどについては、適切なガイドラインに従う必要があります。

あなたの質問に一つずつ答えてみます

* How do you figure out what can be made concurrent vs. what has to be sequential?

同時使用

1)ポーリング:-継続的に何かをポーリングしたり、定期的に更新を送信したりするためのスレッドが必要です。 (ハートビットのような概念は、一定の間隔でデータを中央サーバーに送信して、私が生きていると言っています。)

2)I/Oの多い操作を並列化できます。最良の例はロガーです。ロガースレッドは別のスレッドにすることもできます。

3)異なるデータに対する同様のタスク。異なるデータで発生するが、性質が非常に似ているタスクがある場合、異なるスレッドがこれを行うことができます。最良の例はサーバー要求です。

そしてもちろん、アプリケーションによってはこのような他の多くも同様です。

* How do you reproduce error conditions and view what is happening as the application executes?

ログの使用とログのデバッグ出力。各スレッドで何が起こっているかを確認できるように、スレッドIDもログに記録してください。
エラー状態を生成する1つの方法は、問題が発生していると思われる場所に意図的な遅延(デバッグコード内)を置き、そのスレッドを強制的に停止することです。デバッガでも同様のことができますが、今のところは行っていません。

* How do you visualize the interactions between the different concurrent parts of the application?

ログをロックに入れると、誰が何をいつロックしているか、誰がロックを試みたかがわかります。前に述べたように、各スレッドで何が起こっているかを理解するために、ログにスレッドIDを入れてみてください。

これは、マルチスレッドアプリケーションの開発に約3年間携わってきた私のアドバイスです。

2
Manoj R
  • 並行にすることができるものと順次にする必要があるものをどのように区別しますか?

最初に、アプリケーション(またはコンポーネント)が実際に並行処理のメリットを享受するのか、それとも専門家の言葉で確認するのか-ボトルネックはどこにあるのか?同時実行性は、それを機能させるために必要な投資に必ずしもメリットがあるとは限りません。それが候補のように見える場合は、ボトムアップで作業します-単独で効果的に作業を行うことができる最大の操作または操作のセットを見つけようとします-取るに足らない、コスト効率の悪いスレッドをスピンアップしたくない操作 Actors を探しています。

Erlangでの作業私は、非同期メッセージパッシングと並行性のためのアクターモデルを使用するという概念を絶対に気に入っています。直感的で、効果的で、クリーンです。

オフ アクターの同時実行性を理解する

アクターモデルは、いくつかの主要な原則で構成されています。

  • 共有状態なし
  • 軽量プロセス
  • 非同期メッセージパッシング
  • 着信メッセージをバッファリングするメールボックス
  • パターンマッチングによるメールボックス処理

アクターは、機能を実行するプロセスです。ここで、プロセスは軽量のユーザー空間スレッドです(一般的なヘビー級のオペレーティングシステムプロセスと混同しないでください)。アクターは状態を共有することはないため、共有データにアクセスするためにロックを求めて競合する必要はありません。代わりに、アクターは不変のメッセージを送信してデータを共有します。不変データは変更できないため、読み取りにロックは必要ありません。

Erlang並行性モデルは、データをロックして共有するよりも理解とデバッグが簡単です。ロジックを分離する方法により、コンポーネントにメッセージを渡すことでコンポーネントのテストを簡単に行うことができます。

並行システムでの作業は、これはほとんどの場合、どの言語でも私のデザインがどのように機能するかです。複数のスレッドがデータをプルし、単純な操作を実行して、キューに繰り返しまたはプッシュバックするキューです。 Erlangは、不変のデータ構造を適用して副作用を防止し、新しいスレッドを作成するコストと複雑さを軽減しています。

このモデルはJavaおよび.NETの世界でもこれを作成する方法が存在するため、Erlang専用ではありません- Concurrency and Coordination Runtime(CCR) =および Relang (Jetlang for Javaもあります)。

  • どのようにしてエラー状態を再現し、アプリケーションの実行中に何が起こっているのかを確認しますか?

私の経験では、私ができる唯一のことは、すべてを追跡/記録することへの取り組みです。すべてのプロセス/スレッドには識別子が必要であり、新しい作業単位ごとに相関IDが必要です。ログを調べて、何がいつ処理されたかを正確に追跡できるようにする必要があります。これを排除する魔法はありません。

  • アプリケーションの同時並行部分間の相互作用をどのように視覚化しますか?

上記を参照してください、醜いですが動作します。私が行う他の唯一のことは、UMLシーケンス図を使用することです-もちろんこれは設計時です-しかし、それらを使用して、コンポーネントが意図したとおりに話していることを確認することもできます。

2
Watson

Cは並行性のために設計されていないというあなたの声明には同意しません。 Cは一般的なシステムプログラミング用に設計されており、決定すべき重要な決定を指摘する粘り強さを享受しており、今後何年にもわたってそうします。これは、Cを使用しないことが最善の決定である場合でも当てはまります。さらに、Cでの同時実行性は、設計が複雑であるほど困難です。

私は自分の能力を最大限に発揮して、最終的には本当に実用的ロックのないプログラミングが現実になるかもしれないという考えでロックを実装しようとしています。ロックとは、相互排除を意味するのではなく、単に仲裁を必要とせずに安全な並行性を実装するプロセスを意味します。実用的には、実装するよりも移植しやすいものを意味します。私も正式なCSトレーニングをほとんど受けていませんが、私は望んでもかまいません:)

その後、遭遇するほとんどのバグは比較的浅くなるか、完全に気が遠くなるほど気になって、パブに後退します。 pubが魅力的なオプションになるのは、プログラムをプロファイリングして速度を十分に落とし、探しているものとは関係のない追加のレースを公開した場合のみです。

他の人が指摘したように、あなたが説明する問題は非常にドメイン固有のものです。可能な限りいつでも(プロセス外で)調停が必要になる可能性のあるケースを回避するために最善を尽くします。それが非常に苦痛であると思われる場合は、複数のスレッドまたはプロセスに同時およびシリアル化されていないアクセスを与えるオプションを再評価します。

次に、そこに「分散」を投入すると、仲裁が必須になります。具体的な例はありますか?

1
Tim Post

どのようにしてエラー状態を再現し、アプリケーションの実行中に何が起こっているのかを確認しますか?

アプリケーションの同時並行部分間の相互作用をどのように視覚化しますか?

私の経験に基づくと、これらの2つの側面に対する答えは次のとおりです。

分散トレース

分散トレースは、システムの個々の同時コンポーネントのタイミングデータをキャプチャし、それをグラフィック形式で表示するテクノロジーです。同時実行の表現は常にインターリーブされるため、並列実行されているものとそうでないものを確認できます。

分散トレースは、その起源が(もちろん)分散システムにあり、定義上、非同期で高度に並行しています。分散トレースを備えた分散システムにより、人々は次のことができるようになります。

a)重要なボトルネックを特定する、b)アプリケーションの理想的な「実行」の視覚的表現を取得する、c)同時に実行されている動作を可視化する、d)変更の違いを評価するために使用できるタイミングデータを取得するシステム(強力なSLAがある場合は非常に重要です)。

ただし、分散トレースの結果は次のとおりです。

  1. ネットワーク経由で実行および送信できるコードが増えるため、すべての同時プロセスにオーバーヘッドが追加されます。場合によっては、このオーバーヘッドは非常に重要です。Googleでさえ、ユーザーエクスペリエンスを損なわないように、すべてのリクエストの小さなサブセットでトレースシステムDapperのみを使用します。

  2. 多くの異なるツールが存在しますが、それらのすべてが互いに相互運用できるわけではありません。これはOpenTracingなどの標準によって多少は改善されますが、完全には解決されません。

  3. 共有リソースとその現在のステータスについて何も知らない。アプリケーションコードと、表示されるグラフが示す内容に基づいて、推測することはできますが、この点では便利なツールではありません。

  4. 現在のツールでは、メモリとストレージに余裕があることを前提としています。 timeseriesサーバーのホスティングは、制約によっては、安くはない場合があります。

エラー追跡ソフトウェア

上記のSentryにリンクしているのは、それが最も広く使用されているツールであることと、正当な理由-Sentry Hijackランタイム実行などのエラー追跡ソフトウェアが、発生したエラーのスタックトレースを中央サーバーに同時に転送するためです。

同時実行コードでのこのような専用ソフトウェアの正味の利点:

  1. 重複したエラーは複製されません。つまり、1つ以上の並行システムで同じ例外が発生した場合、Sentryはインシデントレポートをインクリメントしますが、インシデントの2つのコピーを送信しません。

これは、無数の同時エラーレポートを経由する必要なく、どの同時システムでどの種類のエラーが発生しているかを把握できることを意味します。分散システムからの電子メールスパムに遭遇したことがあるなら、あなたは地獄がどんな感じか知っています。

並行システムのさまざまな側面に「タグ付け」することもできます(ただし、これは、スレッドが単にタスク間を効率的にジャンプするだけでイベントハンドラーを処理する必要があるため、技術的には並行していない1つのスレッドにインターリーブされた作業がないことを前提としています。完了まで)タグでエラーの内訳を確認してください。

  1. このエラー処理ソフトウェアを変更して、ランタイム例外の詳細を提供できます。プロセスにはどのようなオープンリソースがありましたか?このプロセスが保持していた共有リソースはありますか?この問題が発生したのはどのユーザーですか?

これにより、綿密なスタックトレース(およびファイルの縮小版を提供する必要がある場合はソースマップ)に加えて、時間の大部分で問題の原因を簡単に特定できます。

  1. (Sentry固有)システムのテスト実行用に個別のSentryレポートダッシュボードを使用して、テストのエラーをキャッチできます。

このようなソフトウェアの欠点は次のとおりです。

  1. すべてのように、彼らはかさばります。たとえば、このようなシステムを組み込みハードウェアで使用したくない場合があります。アイドル状態のマシンで数百回以上の実行をサンプリングした場合としない場合の単純な実行を比較して、このようなソフトウェアの試用を実行することを強くお勧めします。

  2. これらのシステムの多くは暗黙的に例外をキャッチすることに依存しており、すべての言語が堅牢な例外を備えているわけではないため、すべての言語が等しくサポートされているわけではありません。とはいえ、多くのシステムのクライアントがいます。

  3. これらのシステムの多くは本質的にクローズドソースであるため、セキュリティリスクとして発生する可能性があります。そのような場合は、それらを調査する際に十分な注意を払うか、必要に応じて自分で調べてください。

  4. 必要な情報が得られない場合があります。これは、可視性を追加しようとするすべての試みのリスクです。

  5. これらのサービスのほとんどは、並行性の高いWebアプリケーション用に設計されているため、すべてのツールがユースケースに最適であるとは限りません。

要約すると:可視性を持つことは、並行システムの最も重要な部分です。上記の2つの方法は、ハードウェアとデータに関する専用のダッシュボードと組み合わせて、任意の時点でシステムの全体像を把握することで、その側面に対処するために業界全体で広く使用されています。

いくつかの追加の提案

私は、同時発生する問題をひどい方法で解決しようとした人々がコードを修正することに費やす時間よりも多くの時間を費やしました。毎回、次のことが開発者のエクスペリエンスを大幅に改善できるケースを見つけました(これはユーザーエクスペリエンスと同じくらい重要です)。

  • 型に依存します。入力はコードを検証するために存在し、実行時に追加のガードとして使用できます。タイピングが存在しない場合は、アサーションと適切なエラーハンドラーを使用してエラーをキャッチします。並行コードには防御的なコードが必要であり、型は、利用可能な検証の種類として最適です。

    • コンポーネント自体だけでなく、コードコンポーネント間のリンクをテストします。これを本格的な統合テストと混同しないでください。すべてのコンポーネント間のすべてのリンクをテストし、それでも最終状態のグローバル検証のみを探します。これはエラーをキャッチするためのひどい方法です。

良いリンクテストは、あるコンポーネントが別のコンポーネントと分離して通信するとき、メッセージが受信され、メッセージが送信されたかどうかを確認しますあなたが期待するのと同じAAです。共有サービスに依存して通信する2つ以上のコンポーネントがある場合は、それらをすべてスピンアップし、中央サービスを介してメッセージを交換し、最終的にすべてが期待どおりの結果を得ているかどうかを確認します。

多くのコンポーネントを含むテストをコンポーネント自体のテストに分解し、各コンポーネントがどのように通信するかのテストも、コードの有効性の信頼性を高めます。このような厳格なテストの本体を使用すると、サービス間のコントラクトを強制したり、サービスが同時に実行されているときに発生する予期しないエラーをキャッチしたりできます。

  • 適切なアルゴリズムを使用してアプリケーションの状態を検証します。私は、すべてのワーカーを待機しているマスタープロセスがある場合など、簡単なことについて話していますタスクを完了し、すべてのワーカーが完全に完了した場合にのみ次のステップに進みたい-これは、Safraのアルゴリズムなどの既知の方法論が存在するグローバル終了を検出する例です。

これらのツールの一部は言語にバンドルされています。たとえば、Rustはコンパイル時にコードが競合状態にならないことを保証しますが、Goはコンパイル時にも実行される組み込みのデッドロック検出機能を備えています。彼らが生産に達する前に問題を見つけることができれば、それは常に勝利です。

一般的な経験則:並行システムでの障害に対する設計。一般的なサービスがクラッシュまたは破損することを予測します。これは、マシンに分散されていないコードにも当てはまります。単一のマシン上の同時実行コードは、いつでも消えたり削除されたりする可能性がある外部の依存関係(共有ログファイル、Redisサーバー、いまいましいMySQLサーバーなど)に依存する可能性があります。 。

これを行う最良の方法は、アプリケーションの状態を時々検証することです。各サービスのヘルスチェックを行い、そのサービスのコンシューマーにヘルスの異常が通知されるようにします。 Dockerのような最新のコンテナーツールはこれを非常にうまく行うので、サンドボックスに使用する必要があります。

何を並行にすることができ、何を順次にすることができるかをどのように理解しますか?

高度な並行システムでの作業で私が学んだ最大の教訓の1つは、これです(十分なメトリックを持つことは決してできません)。メトリックは、アプリケーションのすべてを完全に駆動する必要があります。すべてを測定していなければ、エンジニアではありません。

指標がないと、いくつかの非常に重要なことを実行できません。

  1. システムの変更によって生じた違いを評価します。チューニングノブAがメトリックBを上げ、メトリックCを下げるかどうかがわからない場合、人々がシステムに予期しない悪意のあるコードをプッシュしたときにシステムを修正する方法がわかりません(そして、コードがシステムにプッシュされます) 。

  2. 物事を改善するために次に何をする必要があるかを理解してください。アプリケーションのメモリが不足していることがわかるまでは、サーバー用にメモリを追加するか、ディスクを購入するかを判断できません。

メトリックは非常に重要で不可欠なので、システムが何を必要とするかについて考える前に、測定したいものを計画することを意識的に努力しました。実際、メトリックは非常に重要なので、それらはこの質問への正しい答えだと思います:プログラムのビットが何をしているかを測定します。適切な設計では、当て推量ではなく数字を使用します。

とはいえ、確かにいくつかの経験則があります。

  1. 順次は依存を意味します。 2つのプロセスは、一方が何らかの方法で他方に依存している場合、順次である必要があります。依存関係のないプロセスは同時に実行する必要があります。ただし、ダウンストリームプロセスが無期限に待機することを妨げないように、上流の障害を処理する方法を計画してください。

  2. I/OバウンドタスクとCPUバウンドタスクを同じコア上で混在させないでください。 (たとえば)同じスレッドで10個の同時要求を起動し、それらが入ってくるとすぐにそれらをスクレイピングし、500にスケーリングすることを期待するWebクローラーを作成しないでください-I/O要求は並列にキューに送られますが、 CPUは引き続きそれらを順番に通過します。 (このシングルスレッドのイベント駆動モデルは人気がありますが、この側面のために制限されています-これを理解するのではなく、人々は単に手を差し伸べてNodeはスケーリングしないと言うだけで、例)。

1つのスレッドで多くのI/O作業を実行できます。ただし、ハードウェアの同時実行性を完全に使用するには、すべてのコアを一緒に占有するスレッドプールを使用します。上記の例では、5つのPythonプロセス(それぞれが6コアマシンのコアを使用できます)をCPU作業用に起動し、6番目のPythonスレッドをI/O専用に起動します。作業は、あなたが考えるよりもはるかに速くスケーリングします。

CPUの同時実行性を利用する唯一の方法は、専用のスレッドプールを使用することです。多くの場合、1つのスレッドで十分なI/Oバウンド作業を行うことができます。これが、Nginxのようなイベント駆動型Webサーバーが、Apache(CPUを必要とするものでI/Oバウンド作業を統合し、リクエストごとにプロセスを起動する)よりも優れている(純粋にI/Oバウンド作業を行う)が、Nodeは、並行して受け取った数万のGPU計算を実行することはひどいアイデアです。

1
Akshat Mahajan

-私の回答はMS/Visual Studio固有です-

並行にすることができるものと、順次にする必要があるものをどのように区別しますか?

それはドメイン知識を取得することになるでしょう、それをカバーするためにここでどんな包括的なステートメントもないでしょう。

どのようにしてエラー状態を再現し、アプリケーションの実行中に何が起こっているのかを確認しますか?

大量のロギング。本番環境でログをオン/オフ/アップして、本番環境でそれをキャッチできます。 VS2010 Intellitrace はこれを支援できるはずですが、まだ使用していません。

アプリケーションの同時並行部分間の相互作用をどのように視覚化しますか?

私にはこれに対する良い答えはありません。見たいと思います。

1
BlackICE

私は鈍くなります。ツールが大好きです。たくさんのツールを使っています。私の最初のステップは、国家の流れの意図された経路をレイアウトすることです。私の次のステップは、それが価値があるかどうか、または必要な情報の流れによってコードが頻繁にシリアル化されるかどうかを試してみることです。次に、いくつかの簡単なモデルをドラフトしてみます。これらは、つまようじの粗い彫刻の積み重ねから、Pythonでのいくつかの単純な同様の例までさまざまです。次に、セマフォの小さな本など、お気に入りの本をいくつか見て、誰かがすでに私の問題に対するより良い解決策を考え出していないかどうかを確認します。

次に、コーディングを開始します。
冗談だ。最初にもう少し研究。私は仲間のハッカーと一緒に座って、プログラムの予想される実行を高レベルでウォークスルーするのが好きです。質問が出た場合は、レベルを下げます。他の誰かがあなたのソリューションを維持するのに十分に理解できるかどうかを知ることが重要です。

最後に、コーディングを開始します。私はまずそれを非常にシンプルに保つようにしています。コードパスだけで、派手なものは何もありません。できるだけ少ない状態に移動します。書き込みを避けます。書き込みと競合する可能性のある読み取りを避けます。何よりも、書き込みと競合する可能性のある書き込みは避けてください。これらの数が非常に有毒であり、美しいソリューションが突然キャッシュスラッシングシリアルアプローチに過ぎないことを見つけるのは非常に簡単です。

可能な限り、フレームワークを使用することをお勧めします。優れた同期データ構造や、神に禁じられている実際の同期プリミティブなど、基本的なスレッドコンポーネントを自分で作成している場合は、ほぼ確実に足全体が吹き飛ばされてしまいます。

最後に、ツール。デバッグは非常に困難です。 Linuxではvalgrind\callgrindをPINと組み合わせて使用​​し、Windowsでは並列スタジオを使用します。このものを手作業でデバッグしないでください。おそらくできます。しかし、おそらくあなたはそうしなかったことを願うでしょう。強力なツールや優れたモデルを10時間マスターすると、数百時間も節約できます。

何よりも、段階的に作業します。慎重に作業してください。疲れているときに並行コードを書かないでください。お腹が空いているときは、書きません。実際、それを回避できる場合は、単に記述しないでください。並行性は困難であり、それを機能としてリストする多くのアプリは、多くの場合、それらを唯一の機能として同梱しています。

要約すれば:
ベギン:
考える
トーク
テスト
簡単に書く
読んだ
テスト
書く
デバッグ
GOTO開始

0
Jake Kurzer

この質問に対する私の答えは次のとおりです。

  • 並行にすることができるものと順次にする必要があるものをどのように区別しますか?

まず、同時実行性を使用する理由を知る必要があります。なぜなら、同時実行性の背後にあるアイデアに人々は飽き飽きしているが、解決しようとしている問題について常に考えているわけではないからです。

キュー、ワークフローなどの実際の状況をシミュレートする必要がある場合は、おそらく並行アプローチを使用する必要があります。

私はそれを使用する必要があることを知ったので、トレードオフを分析する時です、多くのプロセスがある場合、通信オーバーヘッドについて考えるかもしれませんが、新しい必要がある場合、並行ソリューションがなくなる可能性があります(問題を再分析する場合)そう。)

  • どのようにしてエラー状態を再現し、アプリケーションの実行中に何が起こっているのかを確認しますか?

私はこの問題の専門家ではありませんが、並行システムでは、これは正しいアプローチではないと思います。理論的なアプローチを選択して、重要な領域に関する4つのデッドロック要件を探す必要があります。

  1. 非先制
  2. 待って待って
  3. 相互排除
  4. 円形チェーン

    • アプリケーションの同時並行部分間の相互作用をどのように視覚化しますか?

私は、最初にインタラクションの参加者を特定し、次にどのようにして誰とコミュニケーションをとるかを特定しようとします。最後に、グラフと相互作用図は視覚化に役立ちます。私の古き良きホワイトボードは、他のいかなる種類のメディアにも負けません。

0
guiman

さて、検証プロセスのために、大規模な並行システムを設計するとき、私は LTSA-Labeled Transition System Analyser を使用してモデルをテストする傾向があります。それは、並行性分野のベテランで、現在インペリアルのコンピューティング責任者である私の古い家庭教師によって開発されました。

プロジェクト管理の場合と同じように、重要なセクションのスケジュール図を作成する傾向がありますが、同時実行できるものとできないものを解決する限り、それを示すことができる静的アナライザーがあります。次に、同じ操作を繰り返し実行するセクションを特定します。クイックルートはループを見つけるだけです。ループは並列処理のメリットを享受する領域である傾向があるためです。

0
Orbling

何を並行にすることができるか、何をシーケンシャルにする必要があるかをどのように理解しますか?

あなたが書くほとんどすべてのものが同時実行性を利用することができます、特に「征服の考案」のユースケース。はるかに良い質問は、何が同時に行われるべきかということです

Joseph Albahariの C#でのスレッディング には、5つの一般的な使用法がリストされています。

マルチスレッドには多くの用途があります。最も一般的なものは次のとおりです。

レスポンシブなユーザーインターフェースを維持する

並列の「ワーカー」スレッドで時間のかかるタスクを実行することにより、メインのUIスレッドは自由にキーボードとマウスのイベントを処理し続けることができます。

ブロックされたCPUを効率的に使用する

マルチスレッドは、スレッドが別のコンピューターまたはハードウェアの一部からの応答を待っているときに役立ちます。タスクの実行中に1つのスレッドがブロックされている間、他のスレッドは、負荷のないコンピューターを利用できます。

並列プログラミング

集中的な計算を実行するコードは、ワークロードが「分割統治」戦略(パート5を参照)で複数のスレッド間で共有されている場合、マルチコアまたはマルチプロセッサーコンピューターでより高速に実行できます。

投機的実行

マルチコアマシンでは、実行する必要があるかもしれないことを予測し、事前に実行することで、パフォーマンスを改善できる場合があります。 LINQPadはこの手法を使用して、新しいクエリの作成を高速化します。バリエーションは、同じタスクをすべて解決する多数の異なるアルゴリズムを並行して実行することです。どちらが先に「勝ち」、どちらが先に完了するかは、どのアルゴリズムが最も速く実行されるか事前にわからない場合に有効です。

リクエストを同時に処理できるようにする

サーバーでは、クライアント要求は同時に到着する可能性があるため、並行して処理する必要があります(ASP.NET、WCF、Webサービス、またはRemotingを使用する場合、.NET Frameworkはこれに対して自動的にスレッドを作成します)。これは、クライアントでも役立ちます(たとえば、ピアツーピアネットワーキング、またはユーザーからの複数の要求の処理)。

上記のいずれかを実行しようとしないのであれば、おそらくそれについて真剣に考えるほうがよいでしょう。

アプリケーションの実行時にエラー状態を再現し、何が起こっているかをどのように確認しますか?

.NETを使用していて、ユースケースを作成している場合は、 [〜#〜] chess [〜#〜] を使用して、修正をテストできる特定のスレッドインターリービング条件を再作成できます。

アプリケーションの異なる並行部分間の相互作用をどのように視覚化しますか?

それはコンテキストに依存します。労働者のシナリオでは、私はマネージャーの部下だと思います。マネージャーは部下に何かをするように伝え、ステータスの更新を待ちます。

同時に発生する無関係なタスクについては、エレベーターまたは車を別々の車線に配置することを考えています。

同期については、信号機やターンスタイルを時々思います。

また、C#4.0を使用している場合は、 タスク並列ライブラリ を確認することをお勧めします。

0
Conrad Frix