新しい構成の1つではなく、プレーンな古いThreadオブジェクトを使用する方が望ましい場合はありますか?


112

ThreadC#の最近のバージョンでのクラスの使用を回避または推奨するために、ブログの投稿やここSOで多くの人を目にします(もちろん、4.0以上とTask&を追加したことを意味します)。以前にも、プレーンな古いスレッドの機能を多くの場合ThreadPoolクラスで置き換えることができるという事実についての議論がありました。

また、他の特殊なメカニズムにより、醜い+ コンボを置き換えるThreadなど、クラスの魅力がさらに低下しています。TimerThreadSleepBackgroundWorker

それでも、Thread一部の人々(私自身を含む)にとっては非常に親しみやすい概念であり続けるようです。ある種の並列実行を伴うタスクに直面すると、すぐに古き良きThreadクラスを使用するようになります。私は自分のやり方を修正する時がきたのかと最近思っています。

だから私の質問は、Thread上記の構成のいずれかではなく、プレーンな古いオブジェクトを使用することが必要または有用な場合がありますか?


4
nitpick(または多分... :))ではありませんが、それは.NETです(つまり、C#に限定されません)。
MetalMikester

11
これまでのところ、この質問に答えるユーザーの平均的な担当者は64.5kです。かなり印象的なショー
zzzzBov 2012年

1
@zzzzBov:私は自分の答えを投稿することを考えていましたが、今は平均を下げることを恐れることはできません:)
Brian Gideon

@BrianGideon、それであなたや他の誰かがこの質問に答えるのを止めるべき理由はないと思います。
zzzzBov 2012年

@ブライアン・ギデオン:ぜひ投稿してください。:)
チューダー

回答:


107

明らかに、Threadクラスは、あなたが言及する他のすべてのパターンの実装の詳細であるため、廃止することはできません。

しかし、それは本当にあなたの質問ではありません。あなたの質問は

上記の構成の1つではなく、通常のThreadオブジェクトを使用することが必要または役立つ場合はありますか?

承知しました。正確には、上位レベルの構成要素の1つがニーズを満たさない場合。

私のアドバイスは、既存の高抽象化ツールがニーズを満たさない状況にあり、スレッドを使用してソリューションを実装したい場合本当に必要な欠落している抽象化を特定し、その抽象化を実装する必要があるということです。スレッド使用してから、抽象化を使用します。


33
すべての良いアドバイス。しかし、プレーンな古いスレッドオブジェクトが新しい構成の1つよりも好ましい例はありますか?
Robert Harvey

タイミングの問題がある複数のスレッドをデバッグして一部のコードをロードすることは、他の「より高い」レベルの構造を使用するよりもはるかに簡単な場合があります。とにかく、スレッドの操作と使用に関する基本的な知識が必要です。
CodingBarfield 2012年

答えてくれてありがとう、エリック。新しいスレッディング機能に関する最近の砲撃の下で、時々古いスレッドがまだ必要であるということは忘れがたいです。とにかく、ベアメタルの知識はとにかく役に立つと思います。
チューダー

15
@RobertHarvey:はい。たとえば、従来の「プロデューサー/コンシューマー」の状況で、1つのスレッドをワークキューからデータを取り出すための専用スレッドとし、別のスレッドをワークキューにデータを入れるための専用スレッドが必要な場合などです。どちらも永久にループします。これらは、しばらくの間実行するタスクに適切にマッピングされず、結果が得られません。スレッドは2つしかないため、スレッドプールは必要ありません。また、ロックとシグナルを巧みに使用して、他のスレッドを長時間ブロックすることなくキューを安全に保つことができます。
Eric Lippert、2012年

@エリック:TPL Dataflowによってそのような抽象化はすでに提供されていませんか?
Allon Guralnek

52

スレッドは、特定のもの(つまり、並列処理と非同期処理)の基本的な構成要素であるため、削除しないでください。ただしほとんどの人とほとんどのユースケース(一度に2000個のスレッドを生成して、マシンを過負荷にすることなく、並列に多くの小さなジョブを処理する良い方法を提供)などのスレッド・プールなどあなたが言及した使用に、より適切なものは、ありますBackgroundWorker(これは、1つの短期間の作業に役立つイベントをカプセル化します)。

しかし、多くの場合、プログラマーが不必要にホイールを作り直したり、愚かな間違いをしたりするのを防ぐので、それらがより適切であるという理由だけで、それはThreadクラスが廃止されたことを意味しません。これは、上記の抽象化で引き続き使用され、より特殊なクラスでカバーされていないスレッドをきめ細かく制御する必要がある場合にも必要です。

同様に、人々が配列を使用する多くの場合により適している.NETにもかかわらず、配列の使用を禁止しませんList<T>。単に、標準ライブラリでカバーされていないものをビルドしたい場合があるからです。


6
オートマチックトランスミッションが99%の確率で機能するからといって、ドライバーの好みを無視しても、マニュアルトランスミッションに価値がないとは限りません。
Guvante 2012年

4
私がサイクリストで公共交通機関のユーザーであることを考えると、運転慣用句にはあまり詳しくありません。しかし、マニュアルトランスミッションはオートマチックトランスミッションの中心ではありません。スティックを動かす機械的な手ではありません。それは、私が見る限り、実際には他のものを抽象化したものではありません。
ジョーイ

2
2番目の段落で「スレッド」という単語を「アンマネージコード」に置き換えることもできますが、それでも真実です
Conrad Frix

1
@ジョーイ:ああ、私はあなたが陳腐化した一片、使いやすさを犠牲にしてきめ細かい制御を持つことの価値を意味すると思ったが、ほとんどはそれを必要としないであろう。ところで、技術的にはマニュアルトランスミッションの興味深い部分はとにかくクラッチです。
Guvante 2012年

3
実際にトランスミッションのメタファーを使いたい場合、ほとんどのシーケンシャルトランスミッション(BMWのSMGトランスミッションなど)、実際には、コンピューター操作のクラッチとギアセレクターを備えた手動トランスミッションです。これらは、従来のオートマチックのような遊星歯車システムではありません。
アダムロビンソン

13

TaskThreadは異なる抽象化です。スレッドをモデル化する場合Threadでも、クラスは最も適切な選択です。たとえば、現在のスレッドと対話する必要がある場合、これに適したタイプはありません。

ただし、ご指摘のとおり、.NETにはThread、多くの場合よりも望ましいいくつかの専用の抽象化が追加されています。


9

このThreadクラスは廃止されたわけではなく、特別な状況でも役立ちます。

私が作業する場所では、コンテンツ管理システムの一部として「バックグラウンドプロセッサ」を作成しました。ディレクトリ、電子メールアドレス、RSSフィードを監視し、新しいものが表示されるたびにタスクを実行するWindowsサービスです。データ。

これにスレッドプールを使用する試みは機能しませんでした。同時に大量の処理を実行してディスクを破棄しようとするため、Threadクラスを直接使用して独自のポーリングおよび実行システムを実装しました。


ここで直接スレッドを使用することが正しい解決策であるかどうかはわかりませんが、実際にスレッドへの移動が必要な例を示すための+1です。
奇妙なことに、

6

新しいオプションにより、(高価な)スレッドを直接使用および管理する頻度が減ります。

なんらかの並列実行を伴うタスクに直面したときに、古き良きThreadクラスの使用に直接ジャンプする人々。

これは非常に高価であり、並行して処理を行う比較的複雑な方法です。

費用が最も重要であることに注意してください。フルスレッドを使用して小さな仕事を行うことはできません。逆効果になります。ThreadPoolはコストに対抗し、Taskクラスは複雑さ(例外、待機、キャンセル)に対抗します。


5

プレーン・オールド・スレッド・オブジェクトを使用することが必要または有用なケースはありますか?」という質問に答えるために、長時間実行するプロセスがある場合、プレーン・オールド・スレッドは有用です(ただし必須ではありません)。異なるスレッドから相互作用することはありません。

たとえば、ある種のメッセージキューからメッセージを受信するためにサブスクライブするアプリケーションを作成していて、アプリケーションがそれらのメッセージを処理するだけではない場合、スレッドを使用すると便利です。自己完結型(つまり、完了するのを待っていません)であり、短命ではありません。ThreadPoolクラスを使用することは、有効期間が短い一連の作業項目をキューに入れ、新しいスレッドが利用可能になったときにThreadPoolクラスがそれぞれの処理を効率的に管理できるようにするためのものです。タスクは、スレッドを直接使用する場所で使用できますが、上記のシナリオでは、それらがあなたを大いに買うとは思いません。これらは、スレッドをより簡単に操作するのに役立ちます(上記のシナリオでは、


クールで新しい並列処理のほとんどは短期間の細かいタスクを中心に設計されており、長時間実行されるスレッドは引き続きで実装する必要があることに同意しSystem.IO.Threading.Threadます。
Ben Voigt 2012年

4

おそらくあなたが期待していた答えではないかもしれませんが、.NET Micro Frameworkに対してコーディングするときはいつもThreadを使用しています。MFはかなり削減されており、上位レベルの抽象化が含まれておらず、低MHzのCPUからパフォーマンスの最後のビットを取得する必要がある場合、スレッドクラスは非常に柔軟です。


ねえ、それは実際にはかなり良い例です!ありがとう。新しい機能をサポートしていないフレームワークについては考えていません。
Tudor

3

ThreadクラスをADO.NETと比較できます。それは仕事を成し遂げるための推奨ツールではありませんが、時代遅れではありません。他のツールは、仕事を容易にするためにその上に構築されます。

特に必要な機能が提供されていない場合は特に、Threadクラスを他のものの上で使用することは間違いありません。


3

それは間違いなく時代遅れではありません。

マルチスレッド化されたアプリの問題は、正しく取得することが非常に難しいことです(多くの場合、不確定な動作、入力、出力、さらには内部状態も重要です)。プログラマーはできるだけ多くの作業をフレームワーク/ツールにプッシュする必要があります。抽象化してください。しかし、抽象化の致命的な敵はパフォーマンスです。

だから私の質問は、上記の構造のいずれかの代わりにプレーンな古いThreadオブジェクトを使用することが必要または有用な場合はありますか?

深刻なパフォーマンスの問題、高いパフォーマンスの目標がある場合にのみ、スレッドとロックを使用します。


3

スピンアップしたスレッドをカウントして制御する必要がある場合は、常にThreadクラスを使用してきました。スレッドプールを使用してすべての未解決の作業を保持できることはわかっていますが、現在実行中の作業量やステータスを追跡するための良い方法を見つけたことはありません。

代わりに、私はコレクションを作成し、それらをスピンアップした後にそれらにスレッドを配置します-スレッドが行う最後のことは、それ自体をコレクションから削除することです。そうすることで、実行中のスレッドの数を常に知ることができ、コレクションを使用してそれぞれが何を実行しているかを確認できます。すべてを強制終了する必要がある場合は、通常、アプリケーションにある種の「中止」フラグを設定する必要があります。すべてのスレッドがそれ自体で通知して自己終了するのを待ちます-私の場合、私はコレクションをウォークして、それぞれにThread.Abortを発行できます。

その場合、私はThreadクラスを直接操作するより良い方法を見つけていません。Eric Lippertが述べたように、他のものは単に高レベルの抽象化であり、利用可能な高レベルの実装がニーズを満たさない場合は、低レベルのクラスで作業するのが適切です。.NETが正確なニーズに対応していないときにWin32 API呼び出しを行う必要がある場合と同様に、最近の「進歩」にもかかわらず、常にThreadクラスが最良の選択である場合があります。

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