C#4.0では、System.Threading.Tasks名前空間にTask
があります。 Thread
とTask
の本当の違いは何ですか。自分で学習するために、サンプルプログラムをいくつか作成しました(MSDNから取得したヘルプ)。
Parallel.Invoke
Parallel.For
Parallel.ForEach
しかし、アイデアがあまり明確ではないため、多くの疑問があります。
私は最初にStackoverflowで同様の種類の質問を検索しましたが、この質問のタイトルでも同じにはなれませんでした。誰かが以前にここに投稿されているのと同じタイプの質問について知っているならば、親切にリンクの参照をしてください。
タスクはあなたがやりたいことです。
スレッドはそのタスクを実行する多くの可能なワーカーの1つです。
.NET 4.0の用語では、 タスク は非同期操作を表します。スレッドを使用して、作業をチャンクに分割し、別々のスレッドに割り当てることによってその操作を完了します。
コンピュータサイエンスの用語では、Task
は未来またはの約束です。 (これらの2つの用語を同義的に使用する人も、異なる使用法を使用する人もいます。正確な定義に同意できない人もいます。)基本的にTask<T>
は「T
」を返します。今蜂蜜、私はちょっと忙しいです、なぜあなたは後で戻って来ませんか?
Thread
はその約束を果たす方法です。しかし、すべてのTask
が真新しいThread
を必要とするわけではありません。 (実際には、スレッドプールから既存のスレッドを再利用するよりもはるかにコストがかかるので、スレッドを作成するのは望ましくありません。待っている値がファイルシステムまたはデータベースやネットワークの場合は、スレッドが他の要求を処理できるときには待機してデータを待つ必要はありません。代わりに、Task
は、準備ができたら値を受け取るためのコールバックを登録するかもしれません。
特にTask
はとは言いませんと言うわけではありませんそれは値を返すのに非常に長い時間がかかるということです。 計算に長い時間がかかるかもしれませんし、フェッチするには長い時間がかかるかもしれません。前者の場合のみ、Thread
を実行するためにTask
を使用します。 (.NETでは、スレッドは非常に高価になっているので、一般的にはできるだけスレッドを避け、複数のCPUで複数の重い計算を実行したい場合にのみ使用します。たとえば、Windowsでは、スレッドの重量は12KiByte(私の考えでは、Linuxではスレッドの長さは4 Kバイト、Erlang/BEAMではわずか400バイト、.NETでは1 Mバイトです。)
ベアメタルなので、おそらく使う必要はないでしょう。おそらくLongRunning
タスクを使って、.NET Framework 4(2002年2月)以降に含まれているTPL - タスク並列ライブラリの恩恵を受けることができます。 NETコア)。
スレッドの上の抽象化。これはスレッドプールを使用します(タスクをLongRunning
操作として指定しない限り、指定した場合は、新しいスレッドがフードの下に作成されます)。
名前が示すように、スレッドのプール。 .NETフレームワークは限られた数のスレッドを処理していますか。どうして?わずか8コアのプロセッサ上で高価なCPU操作を実行するために100個のスレッドを開くのは、絶対にお勧めできません。フレームワークはあなたのためにこのプールを維持し、スレッドを再利用し(各操作でそれらを作成したり殺したりしないで)、そしてあなたのCPUが燃えないようにそれらのいくつかを並列に実行します。
再開にあたって:常にタスクを使用する。
タスクは抽象化されているので、はるかに使いやすいです。私はあなたがいつもタスクを使うことを試みることを勧めます、そしてあなたがあなた自身でスレッドを扱う必要があるような問題に直面するなら(おそらく1%の時間)それからスレッドを使うこと。
LongRunning
を使用してください。タスク(またはが必要な場合はスレッド)。タスクを使用すると、少数のスレッドがビジー状態になり、プールを占有する順番を待っている別のタスクが多数存在するスレッドプールに移動します。Task
を使用して何をしたいのかを指定してから、そのTask
をThread
に添付することができます。そのため、Task
は、GUIスレッドではなく、新しく作成されたThread
で実行されます。
Task
をTaskFactory.StartNew(Action action)
と共に使用します。ここではデリゲートを実行するので、スレッドを使用していなければ、同じスレッド(GUIスレッド)で実行されます。スレッドに言及した場合は、このTask
を別のスレッドで実行できます。これは不要な作業です。デリゲートを直接実行するか、そのデリゲートをスレッドにアタッチしてそのスレッドで実行することができます。だからそれを使わないでください。それはただ不要です。あなたのソフトウェアを最適化するつもりなら、これは削除されるべき良い候補です。
** Action
はdelegate
です。
上記の点に加えて、以下のことを知っておくとよいでしょう。
私は通常、Task
を使ってWinformsや単純なバックグラウンドワーカーとやり取りし、UIがフリーズしないようにします。これは私がTask
を使うことを好むときの例です
private async void buttonDownload_Click(object sender, EventArgs e)
{
buttonDownload.Enabled = false;
await Task.Run(() => {
using (var client = new WebClient())
{
client.DownloadFile("http://example.com/file.mpeg", "file.mpeg");
}
})
buttonDownload.Enabled = true;
}
VS
private void buttonDownload_Click(object sender, EventArgs e)
{
buttonDownload.Enabled = false;
Thread t = new Thread(() =>
{
using (var client = new WebClient())
{
client.DownloadFile("http://example.com/file.mpeg", "file.mpeg");
}
this.Invoke((MethodInvoker)delegate()
{
buttonDownload.Enabled = true;
});
});
t.IsBackground = true;
t.Start();
}
違いはMethodInvoker
とそれより短いコードを使う必要がないということです。