スレッドの作成-Task.Factory.StartNew vs new Thread()


102

.Net 4の新しいスレッドおよび並列ライブラリについて学んでいるところです。

以前は、次のようにして(例として)新しいスレッドを作成しました。

DataInThread = new Thread(new ThreadStart(ThreadProcedure));
DataInThread.IsBackground = true;
DataInThread.Start();

今私はできる:

Task t = Task.Factory.StartNew(() =>
{
   ThreadProcedure();
});

どんな違いがありますか?

ありがとう


1
スレッドプールスケジューラのしくみについて少し心配する必要があります。それは大きな違いを生む可能性がありますが、それはすべて、スレッド内で実際に行うことによって異なります。
ハンスパッサント

回答:


79

大きな違いがあります。タスクはThreadPoolでスケジュールされ、必要に応じて同期的に実行することもできます。

長時間のバックグラウンド作業がある場合は、正しいタスクオプションを使用してこれを指定する必要があります。

最適化されているため、明示的なスレッド処理よりもタスク並列ライブラリを使用することをお勧めします。また、あなたは継続のようなより多くの機能を持っています。


5
いいえ、ありません。タスクを開始するだけです。これにより、スレッドプールでタスクがキューに入れられるか、同期的に実行されます。TPLは、(コアを利用することのように)スレッド/並行処理を自分で管理するからあなたを解放し、ご使用のプラットフォームのための最善の使用についてです
sanosdole

10
常に別のスレッドを作成するTaskCreationOptions.LongRunningオプションがありますが、全体の要点は、なぜ別のスレッドが必要なのですか?並行して何かを実行したいだけの場合(Mainはタスクの実行中にsthを実行します)、最適化されたライブラリに、スレッドなどのシステムリソースを最も効率的な方法で利用する方法を決定させることをお勧めします。
sanosdole

3
このmsdnの記事では、タスクのスケジュール方法について説明しています。長期実行とインライン化(​​同期実行)について説明します。msdn.microsoft.com/en-us/library/dd997402.aspx
sanosdole

2
@sming重要なのは、新しいスレッドが欲しいということではなく、同時に処理したい(UIをブロックしないで)ことです。ThreadPoolはUIスレッドをブロックしませんが、スレッドを作成して手動で行うよりもはるかに効率的にバックグラウンドスレッドを管理します。それは、TPLが導入するマインドプロセスの変化です。スレッドではなく、並行タスクを考えてください。
sanosdole 2014年

4
@sming申し訳ありませんが、その文は少し粗すぎました。タスクの同期実行はインライン化と呼ばれます。UIスレッドからスレッドプール(デフォルトスケジューラ)でタスクをスケジュールする場合、タスクは発生しません。アンビエントスケジューラー( 'TaskScheduler.Current')が '.Wait()'を呼び出すタスクのスケジューラーと同じ場合にのみ発生します。'.Wait()'はブロックしているため、とにかくUIをブロックします。Short:waitを呼び出さないでください。同期して実行されません。
sanosdole 2014年

73

タスクはタスクAPIのすべての優れた点を提供します。

  • 継続の追加(Task.ContinueWith
  • 複数のタスク(すべてまたはいずれか)が完了するのを待つ
  • タスクのエラーをキャプチャし、後で問い合わせる
  • キャンセルのキャプチャー(および最初にキャンセルを指定できるようにする)
  • 潜在的に戻り値がある
  • C#5でawaitを使用する
  • スケジューリングをより適切に制御します(実行に時間がかかる場合は、タスクを作成するときにタスクスケジューラがそれを考慮できるように、そのように伝えます)。

どちらの場合でも、メソッドグループ変換を使用すると、コードを少し単純にすることができます。

DataInThread = new Thread(ThreadProcedure);
// Or...
Task t = Task.Factory.StartNew(ThreadProcedure);

8
+1。私はそれを追加したいと思いThreadますTask(詳細なブログ投稿があります)。グランドラピッズDevDayで「現実世界でのタスクの使用」のような講演を行っています。(スレッドをThread実装している場合を除いてTaskScheduler)もはや必要がないため、この話は「スレッドはデッド」と呼ばれます。
Stephen Cleary

@StephenCleary、私はあなたThreadがバックグラウンドスレッドとして使用されることになると、死んでいることを意味すると思いますか?
引き潮

1
@ebb:いいえ、最初のコメントで述べたより強力な立場をとります。何もありませんThread行うことができます(またはBackgroundWorker)で、よりエレガントに行うことはできませんTaskし、適切なはTaskScheduler
スティーブンクリアリー2010年

1
@StephenCleary、使用せずに専用スレッドをどのように作成しThreadますか?
2010年

4
@ebb:「専用スレッド」は私にはわかりません。Task特定のスレッドでを実行する場合は、適切なものを使用しますTaskScheduler(例:)AsyncContextThread。ただし、これは通常必要ありません。SynchronizationContextThreadPool、およびConcurrentExclusiveSchedulerPairスケジューラは、ほとんどのプログラムで十分です。
スティーブンクリアリー2010年

12

前者の場合は単に新しいスレッドを開始しているのに対して、後者の場合はスレッドプールに入るだけです。

スレッドプールのジョブが共有し、リサイクルのスレッドにあります。これにより、新しいスレッドを作成する必要があるたびに数ミリ秒を失うことを回避できます。

スレッドプールに入る方法はいくつかあります。

  • TPLあなたが行ったように(タスク並列ライブラリ)
  • ThreadPool.QueueUserWorkItemを呼び出す
  • デリゲートでBeginInvokeを呼び出す
  • BackgroundWorkerを使用する場合

1

コードの最初のブロックは、バックグラウンドとして実行できるスレッド(たとえばT)を作成するようにCLRに指示します(Tをスケジュールするときにスレッドプールスレッドを使用します)。簡潔に言えば、何かを行うためのスレッドを作成するようCLRに明示的に要求し、そのスレッドでStart()メソッドを呼び出して開始します。

コードの2番目のブロックは同じことを行いますが、タスクファクトリ実装のStartNewメソッドを介してスレッド(バックグラウンド-スレッドプールで再度実行されます)と開始スレッドを作成する責任を委任(暗黙的にハンドオーバー)します。

これは、与えられたコードブロック間の迅速な違いです。そうは言っても、グーグルや私の仲間の貢献者からの他の回答を見ることができる詳細な違いはほとんどありません。

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