並行性:設計にどのようにアプローチし、実装をデバッグしますか?


37

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

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

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

  • 並行処理できるものとシーケンシャルにする必要があるものをどのように把握しますか?
  • エラー状態を再現し、アプリケーションの実行中に何が起こっているかを表示するにはどうすればよいですか?
  • アプリケーションの異なる並行部分間の相互作用をどのように視覚化しますか?

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

編集

これまでのところ、多くの良い入力があります。リンクされている記事の多くは非常に優れており、私はすでにそれらのいくつかを読みました。

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

バウンティの目標

何をすべきか教えてはいけません。私はすでにそれをコントロールしています。あなたが何をするか教えてください。これらの問題の解決方法教えてください。


これは良い質問です-多くの可能な深さ。また、Javaでのマルチスレッドアプリケーションの良い経験もいくつか得ましたが、もっと学びたいです。
マイケルK

これまでのところ、いくつかの良い答えがあります。誰もあなたがこの分野であなたを助けたいと思ったものに突き刺したいですか?
ベリンロリッチ

同時コーディング用のTotalView Debuggerは非常に便利なツールですが、少し学習曲線が必要です-totalviewtech.com/products/totalview.html
Fanatic23

ロギングは、最後の2つの質問に役立つかもしれません。
アミールRezaei

私が探しているのは、人々のプロセスです。これらは、私が使用してきたツールでは不十分ですが、仕事を成し遂げることができる分野です。他の人の記事を引用することについてはあまり気にせず、ここで方法論にもっと気を配ります。
ベリンロリチュ

回答:


11

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

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

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

はい

並行処理できるものとシーケンシャルにする必要があるものをどのように把握しますか?

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

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

最近、私はscalaでActorを発見しました。私の古いソリューションは一種の「ミニアクタ」であり、scalaのものよりはるかに強力ではないことがわかりました。ですから、私の提案はそこから始めることです。

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

とにかくscalaを使えば、ずっと簡単です。

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

ここに本当の答えはありません。並行性のユニットテストがいくつかあり、アプリケーションにできる限り負荷をかける負荷テストスイートがあります。

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

繰り返しますが、本当の答えはありません。メタファーをホワイトボード上で設計し、建築面で矛盾がないようにします。

ここでのArchの意味は、Neal Fordの定義です。SwArchitectureは、後で変更するのが非常に難しいすべてです。

プログラミングは、シーケンシャルプログラミングとは異なる考え方が必要だと私を信じさせます。

たぶん、しかし私にとっては平行して考えることは単に不可能なので、並行思考を必要としない方法でソフトウェアを設計し、並行レーン間のクラッシュを避けるために明確なガードレールを使用してください。


6

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

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

説明のために、(それほど簡単ではない)ストーリー:

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

問題をさらに調査すると、いくつかのコンピューター間で計算を並列化できることが明らかになりましたが、古いデータベースサーバー(SQL 6.5をエミュレートするSQL 2000サーバー)には依然として大きなボトルネックがあります。

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

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

2)複数のマシン上の複数のコンシューマ。各消費者は、キューからデータのパケット全体を受信し、すぐに計算できます。各デキュー操作は同期されます。

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

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

SQL 6.5の不適切な同時実行管理によって引き起こされた保持の問題を取り除くだけで、大きな利点が得られました。残りはほぼ線形で、「グリッド」に新しいコンピューターを追加するたびに、データベースに対する順次読み取り/書き込み操作の「最大効率」に達するまで処理時間が短縮されました。


2

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

あなたの質問に一つずつ答えてみましょう

* 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
  • 並行処理できるものとシーケンシャルにする必要があるものをどのように把握しますか?

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

Erlangを使用して、非同期メッセージパッシングと並行性のためのアクターモデルを使用するという概念が大好きになりました。直感的、効果的、クリーンです。

アクターの同時実行性理解から

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

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

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

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

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

このモデルは、Erlang専用ではありません。Javaおよび.NETの世界にも、これを作成する方法があります。同時実行および調整ランタイム(CCR)およびRelang(Jetlang for Javaもあります)を検討します。

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

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

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

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


1

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

並行処理できるものとシーケンシャルにする必要があるものをどのように把握しますか?

それにはドメインの知識が必要になりますが、それをカバーする包括的な説明はここにはありません。

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

本番アプリケーションでログをオン/オフ/アップして、本番環境でキャッチできるようにすることができます。 VS2010 Intellitraceはこれを支援できるはずですが、まだ使用していません。

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

私はこれに良い答えを持っていません、それを見たいです。


ロギングはコードの実行方法を変更するため、表示されなかった後にエラーが発生する可能性があります。
マシューリード

1

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

私は、最終的には真に実用的なロックフリープログラミングが私にとって現実になるかもしれないという考えで、ロックを実装するために最大限の努力をします。ロックとは、相互排除を意味するのではなく、調停を必要とせずに安全な並行性を実装するプロセスを意味するだけです。実際には、実装よりも移植が簡単なものを意味します。正式なCSトレーニングもほとんどありませんが、私は希望することが許されていると思います:)

それに続いて、私が遭遇するほとんどのバグは比較的浅くなるか、パブに退却することを完全に気が遠くなるように気にします。pubが魅力的なオプションになるのは、プログラムのプロファイリングによって、私が探しているものとは関係のない追加の競合を公開するのに十分なほど遅くなる場合だけです。

他の人が指摘したように、あなたが説明する問題は非常にドメイン固有です。私は、できる限り調停を必要とする可能性のあるケース(プロセスの外部)を回避できるように、できる限り努力しています。それが堂々たる痛みのように見える場合、複数のスレッドまたはプロセスに何かへの同時および非シリアル化アクセスを与えるオプションを再評価します。

そして再び、そこに「分散」を投げ込み、仲裁が必須になります。具体的な例はありますか?


私の声明を明確にするために、Cは並行性専用に設計されたわけではありません。これは、並行性を念頭に置いて明示的に設計されたGo、Erlang、Scalaなどの言語とは対照的です。私はあなたがCで並行処理を行うことができないと言うつもりはないた
Berin Loritsch

1

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

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

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

分散トレース

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

分散トレースは、(もちろん)非同期システムであり、高度に同時実行される(もちろん)分散システムに由来しています。分散トレースを備えた分散システムにより、人々は次のことが可能になります。

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

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

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

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

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

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

エラー追跡ソフトウェア

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

並行コードにおけるこのような専用ソフトウェアの最終的な利点:

  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. シーケンシャルは依存性を意味します。1つのプロセスが何らかの方法で他のプロセスに依存している場合、2つのプロセスは連続している必要があります。依存関係のないプロセスは並行でなければなりません。ただし、ダウンストリームのプロセスが無期限に待機することを妨げない、上流の障害を処理する方法を計画します。

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

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

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


0

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

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


0

並行処理できるものとシーケンシャルにする必要があるものをどのように把握しますか?

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

Joseph AlbahariのC#スレッド化には、 5つの一般的な用途がリストされています。

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

レスポンシブユーザーインターフェイスの維持

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

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

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

並列プログラミング

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

投機的実行

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

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

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

上記のいずれかを実行しようとしていない場合は、おそらくそれについて真剣に考えた方がよいでしょう。

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

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

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

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

無関係なタスクを同時に行う場合、エレベータや車は別々の車線にあると思います。

同期のために、私は時々信号機やターンスタイルを考えます。

また、C#4.0を使用している場合は、タスク並列ライブラリをご覧ください。


0

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

  • 並行処理できるものとシーケンシャルにする必要があるものをどのように把握しますか?

最初に、なぜ並行性を使用する必要があるのか​​を知る必要があります。なぜなら、人々は並行性の背後にあるアイデアから退出することがわかったが、解決しようとしている問題について常に考えるとは限らないからです。

キュー、ワークフローなどの現実の状況をシミュレートする必要がある場合、ほとんどの場合、並行アプローチを使用する必要があります。

トレードオフを分析する時間を使用する必要があることを知ったので、多くのプロセスがある場合は通信のオーバーヘッドを考えるかもしれませんが、新しい必要がある場合は、同時解決策がない場合があります(問題を再分析する場合そう。)

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

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

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

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

私は最初に誰が対話の参加者であるかを特定し、次にどのように誰と通信するのかを特定しようとします。最後に、グラフと相互作用図は視覚化に役立ちます。私の古き良きホワイトボードは、他の種類のメディアには負けません。


0

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

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

最後に、コーディングを開始します。私は最初にそれを非常にシンプルにしようとします。コードパスだけで、何も凝ったものではありません。できるだけ少ない状態に移動します。書き込みを避けます。書き込みと競合する可能性のある読み取りは避けてください。何よりも、書き込みと競合する可能性のある書き込みを避けてください。これらの有害な数の正の数を持っていること、そしてあなたの美しい解決策はキャッシュスラッシングシリアルアプローチに比べて突然であることがすぐにわかります。

できる限りフレームワークを使用することをお勧めします。適切な同期データ構造や、神に禁じられている実際のシンクロプリミティブなど、基本的なスレッドコンポーネントを自分で記述している場合、ほぼ間違いなく足を吹き飛ばすことになるでしょう。

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

何よりも、段階的に作業します。慎重に作業してください。疲れたときに並行コードを書かないでください。おなかがすいているときに書かないでください。実際、それを避けることができれば、単にそれを書かないでください。同時実行は困難であり、機能としてリストする多くのアプリは、多くの場合、それを唯一の機能として出荷します。

要約:
開始:
考えて
話して
テスト
書き込み単に
読み取り
テスト
書き込み
デバッグ
GOTOを開始

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.