私は最近、イーサネットとシリアルを介してメッセージを送受信するアプリケーションに取り組んでいました。次に、 add DIOディスクリートの監視を任されました。私は、
「メッセージ処理に関係するメインスレッドを中断する理由はありません。DIOを監視する別のスレッドを作成します。 。」
ただし、この決定は悪いであることが判明しました。シリアルメッセージの送信と受信の間でメインスレッドが中断されることがありました。この中断はタイミングを混乱させ、残念ながら、メッセージは(永久に)失われます。
別のスレッドを使用せずにDIOを監視する別の方法を見つけましたイーサネットとシリアル通信が正しい機能に復元されました。
しかし、大失敗全体が私に考えさせられました。 notがマルチスレッドを使用する場合、および/またはマルチスレッドを使用する場合の状況の例がもうない場合についての一般的なガイドラインはありますか良いアイデアですか?
**編集:あなたのコメントに基づいて、情報を得るためにインターネットを調べた後、私は というタイトルのブログ投稿を作成しました。マルチスレッドはいつ良い考えではありませんか?
合計すると、デスクトップアプリのフリーズ解除やその他の一般的な回答以外に複数のスレッドを使用すると、アプリの速度が低下しますifスレッドが相互に中断するため、単一のコアマシンがあります。
どうして?ハードウェアスイッチのため。ハードウェアがスレッドを切り替えるには、合計で時間がかかります。マルチコアボックスでは、先に進み、コアごとに1つのスレッドを使用すると、大幅に増加します。
古い引用を言い換えると、プログラマーに問題がありました。彼は「わかっている、スレッドを使う」と思った。現在、プログラマーには2つの問題があります。 (多くの場合、JWZに起因しますが、正規表現について話している彼の使用よりも前のようです。)
経験則として、「スレッドを使用する非常に説得力のある理由がない限り、スレッドを使用しないでください」です。複数のスレッドが問題を求めています。複数のスレッドを使用せずに問題を解決するための良い方法を見つけてください。スレッドを使用するための余分な労力と同じくらい問題が発生しない場合にのみ、スレッドの使用にフォールバックしてください。また、マルチコア/マルチCPUマシンで実行している場合は、複数のスレッドに切り替えることを検討してください。シングルスレッドバージョンのパフォーマンステストでは、追加のコアのパフォーマンスが必要であることが示されています。
実際、マルチスレッドはスケーラブルではなく、デバッグが難しいため、回避できる場合は、どのような場合でも使用しないでください。マルチCPUでのパフォーマンスが重要な場合や、多数のクライアントが応答に時間がかかるサーバーを扱う場合など、必須の場合はほとんどありません。
それ以外の場合は、キュー+ cronジョブなどの代替手段を使用できます。
複数のデータソース/シンクの処理に関するDanKegelの " C10K問題 " Webページを参照することをお勧めします。
基本的に、最小限のスレッドを使用するのが最善です。これは、ソケットでは、ほとんどのOSでイベントシステムを使用して実行できます(または、WindowsではIOCPを使用して非同期で実行できます)。
OSやライブラリが非ブロッキング方式で通信を実行する方法を提供していない場合は、スレッドプールを使用して、同じイベントループに報告しながらそれらを処理するのが最善です。
レイアウト図の例:
Per CPU [*] EVENTLOOP ------ Handles nonblocking I/O using OS/library utilities
| \___ Threadpool for various blocking events
Threadpool for handling the I/O messages that would take long
マルチスレッドは、それが良い単一の場合を除いて悪いです。この場合は
これらの条件のいずれかまたは両方が欠落している場合、マルチスレッドは勝利の戦略にはなりません。
作業がCPUにバインドされていない場合は、スレッドが作業を終了するのを待っているのではなく、プロセスが作業を完了するのをネットワークアクティビティなどの外部イベントで待っています。スレッドを使用すると、スレッド間のコンテキスト切り替えの追加コスト、同期のコスト(ミューテックスなど)、およびスレッドプリエンプションの不規則性が発生します。最も一般的に使用される代替手段は非同期IOです。この場合、単一のスレッドが複数のioポートをリッスンし、現在準備ができている方に一度に1つずつ動作します。万が一、これらの遅いチャネルがすべて同時に準備ができた場合、速度が低下するように見えるかもしれませんが、実際にはこれが当てはまることはめったにありません。多くの場合、各ポートを個別に処理するコストは、各チャネルが空になったときに複数のスレッドで状態を同期するコストと同等かそれ以上です。
多くのタスクはコンピューティングバウンドである可能性がありますが、プロセスは状態全体で同期する必要があるため、マルチスレッドアプローチを使用することは実用的ではありません。このようなプログラムは、作業を同時に実行できないため、マルチスレッドの恩恵を受けることはできません。幸い、膨大な量のCPUを必要とするほとんどのプログラムは、ある程度並列化できます。
私が書いた最近のアプリケーションhadマルチスレッドを使用する(スレッドの数に制限はありませんが)は、2つのプロトコルを介して複数の方向で通信し、3番目のリソースの変更を監視する必要があるアプリケーションでした。両方のプロトコルライブラリは、それぞれのイベントループを実行するためにスレッドを必要とし、それらが考慮されると、リソース監視用の3番目のループを簡単に作成できました。イベントループの要件に加えて、ワイヤを通過するメッセージには厳密なタイミング要件があり、一方のループが他方をブロックするリスクを冒すことはできませんでした。これは、マルチコアCPU(SPARC)を使用することでさらに軽減されました。
各メッセージ処理をスレッドプールからスレッドに与えられたジョブと見なすべきかどうかについてさらに議論がありましたが、結局、それは作業する価値のない拡張でした。
全体として、スレッドは可能であれば、セマンティクスの文書化と実装が比較的簡単で、上限を設定できるように、明確に定義されたジョブ(または一連のジョブ)に作業を分割できる場合にのみ検討する必要があります。使用し、相互作用する必要のあるスレッドの数。これが最適に適用されるシステムは、ほとんどメッセージパッシングシステムです。
正確な物理的タイミングを保証する必要がある場合(例のように)、マルチスレッドはお勧めできません。その他の短所には、スレッド間の集中的なデータ交換が含まれます。マルチスレッドは、相対的な速度/優先度/タイミングをあまり気にしないのであれば、本当に並列のタスクに適していると思います。
マルチスレッドは一般的に次の目的で使用されます。
したがって、これらの問題の1つを解決していない場合、スレッドを追加することで作業が楽になる可能性はほとんどありません。実際、他の人が言及しているように、それはほぼ確実にそれを難しくします。マルチスレッドアプリケーションのデバッグは、シングルスレッドソリューションよりもかなり多くの作業が必要です。
セキュリティは、(複数のプロセスで)複数のスレッドを使用しないようにする理由になる場合があります。マルチプロセスの安全機能の例については、 Google chrome を参照してください。
スレッドを使用する理由として考えられるものがさらにいくつかあります。
集中的な処理中にGUIの応答性を維持するために、必ずしも追加のスレッドが必要になるとは限りません。通常、単一のコールバック関数で十分です。
上記のいずれにも当てはまらず、何らかの理由で並列処理が必要な場合は、可能であれば独立したプロセスを開始することをお勧めします。
原則として、呼び出し元がキューで待機するオーバーヘッドはありません。
マルチスレッドはスケーラブルであり、バックグラウンドで非常に複雑なことを実行しながら、UIがその応答性を維持できるようにします。他の回答がマルチスレッドに関する情報をどこで取得しているのかわかりません。
マルチスレッドを使用すべきでない場合は、問題に対する誤解を招く質問です。あなたの問題はこれです:なぜ私のアプリケーションをマルチスレッド化するとシリアル/イーサネット通信が失敗するのですか?
その質問への答えは実装によって異なりますが、これについては別の質問で説明する必要があります。マルチスレッドアプリケーションで、データを失うことなく、他の多くのタスクと同時にイーサネット通信とシリアル通信の両方を実行できることを私は知っています。
マルチスレッドを使用しない理由の1つは、次のとおりです。
マルチスレッドを使用する理由は次のとおりです。
マルチスレッドプログラミングには、スレッドセーフを簡単に実装できる3つの基本的な方法があります。成功するには1つだけを使用する必要があります。
スレッドの問題の一般的な原因は、データを同期するために採用される通常のアプローチです。スレッドに状態を共有させてから、適切なすべての場所にロックを実装することは、設計とデバッグの両方の複雑さの主な原因です。安定性、パフォーマンス、およびスケーラビリティのバランスをとるためにロックを正しく行うことは、常に解決するのが難しい問題です。最も経験豊富な専門家でさえ、それを頻繁に間違えます。スレッド化を処理するための代替手法は、この複雑さの多くを軽減できます。 Clojure プログラミング言語は、並行性を処理するためのいくつかの興味深い手法を実装しています。
プロセスは並行していますか?パフォーマンスは本当に懸念事項ですか? Webサーバーのように、実行の「スレッド」が複数ありますか?有限の答えはないと思います。