過去数日間、.net 4.5とc#5の新機能をテストしました。
新しい非同期/待機機能が気に入っています。以前、BackgroundWorkerを使用して、応答性の高いUIでバックグラウンドでより長いプロセスを処理していました。
私の質問は次のとおりです。これらの素晴らしい新機能を使用した後、いつasync / awaitを使用する必要があり、いつBackgroundWorkerを使用しますか?両方に共通するシナリオはどれですか?
過去数日間、.net 4.5とc#5の新機能をテストしました。
新しい非同期/待機機能が気に入っています。以前、BackgroundWorkerを使用して、応答性の高いUIでバックグラウンドでより長いプロセスを処理していました。
私の質問は次のとおりです。これらの素晴らしい新機能を使用した後、いつasync / awaitを使用する必要があり、いつBackgroundWorkerを使用しますか?両方に共通するシナリオはどれですか?
回答:
async / awaitは、などの構成を置き換えるように設計されていBackgroundWorker
ます。あなたは確かにいる間ことができ、それを使用するあなたがしたい場合は、そこだすべてを処理するために、いくつかの他のTPLツールと一緒に、非同期/のawaitを使用することができるはずです。
どちらも機能するので、いつどのように使用するかは個人の好みに帰着します。あなたにとって何がより速いですか?あなたが理解しやすいのは何ですか?
async
/ await
は、スレッドプールスレッドなしの非同期プログラミングも許可することに注意してください。
これはおそらく多くの場合TL; DRですが、比較await
することBackgroundWorker
はリンゴとオレンジを比較するようなものだと思います。
BackgroundWorker
は、バックグラウンドでスレッドプールスレッドに対して実行する単一のタスクをモデル化するためのものです。 async
/ await
は、非同期操作で非同期に待機するための構文です。これらの操作は、スレッドプールスレッドを使用する場合と使用しない場合があります。つまり、リンゴとオレンジです。
たとえば、次のようなことができますawait
:
using (WebResponse response = await webReq.GetResponseAsync())
{
using (Stream responseStream = response.GetResponseStream())
{
int bytesRead = await responseStream.ReadAsync(buffer, 0, buffer.Length);
}
}
ただし、バックグラウンドワーカーでモデル化することはおそらくないでしょう。.NET4.0では、次のようなことをするでしょう(以前はawait
)。
webReq.BeginGetResponse(ar =>
{
WebResponse response = webReq.EndGetResponse(ar);
Stream responseStream = response.GetResponseStream();
responseStream.BeginRead(buffer, 0, buffer.Length, ar2 =>
{
int bytesRead = responseStream.EndRead(ar2);
responseStream.Dispose();
((IDisposable) response).Dispose();
}, null);
}, null);
2つの構文間で比較された破棄のばらばらさと、/ using
なしでは使用できないことに注意してください。async
await
しかし、そのようなことをで行うことはありませんBackgroundWorker
。 BackgroundWorker
通常は、UIの応答性に影響を与えたくない単一の長時間実行オペレーションをモデル化するためのものです。例えば:
worker.DoWork += (sender, e) =>
{
int i = 0;
// simulate lengthy operation
Stopwatch sw = Stopwatch.StartNew();
while (sw.Elapsed.TotalSeconds < 1)
++i;
};
worker.RunWorkerCompleted += (sender, eventArgs) =>
{
// TODO: do something on the UI thread, like
// update status or display "result"
};
worker.RunWorkerAsync();
async / awaitで使用できるものは何もなくBackgroundWorker
、スレッドを作成しています。
これで、代わりにTPLを使用できます。
var synchronizationContext = TaskScheduler.FromCurrentSynchronizationContext();
Task.Factory.StartNew(() =>
{
int i = 0;
// simulate lengthy operation
Stopwatch sw = Stopwatch.StartNew();
while (sw.Elapsed.TotalSeconds < 1)
++i;
}).ContinueWith(t=>
{
// TODO: do something on the UI thread, like
// update status or display "result"
}, synchronizationContext);
この場合、TaskScheduler
はスレッドを作成し(デフォルトはTaskScheduler
)、await
次のように使用できます。
await Task.Factory.StartNew(() =>
{
int i = 0;
// simulate lengthy operation
Stopwatch sw = Stopwatch.StartNew();
while (sw.Elapsed.TotalSeconds < 1)
++i;
});
// TODO: do something on the UI thread, like
// update status or display "result"
私の意見では、主要な比較は、進捗状況を報告しているかどうかです。たとえば、BackgroundWorker like
これがあるかもしれません:
BackgroundWorker worker = new BackgroundWorker();
worker.WorkerReportsProgress = true;
worker.ProgressChanged += (sender, eventArgs) =>
{
// TODO: something with progress, like update progress bar
};
worker.DoWork += (sender, e) =>
{
int i = 0;
// simulate lengthy operation
Stopwatch sw = Stopwatch.StartNew();
while (sw.Elapsed.TotalSeconds < 1)
{
if ((sw.Elapsed.TotalMilliseconds%100) == 0)
((BackgroundWorker)sender).ReportProgress((int) (1000 / sw.ElapsedMilliseconds));
++i;
}
};
worker.RunWorkerCompleted += (sender, eventArgs) =>
{
// do something on the UI thread, like
// update status or display "result"
};
worker.RunWorkerAsync();
あなたが行うことができない何かを-しかし、あなたはドラッグ&ドロップ形式の設計面へのバックグラウンドワーカーコンポーネントをしたいので、この一部に対処しませんasync
/ await
とTask
あなたが「勝った...つまり、 tオブジェクトを手動で作成し、プロパティを設定し、イベントハンドラーを設定します。あなただけのボディを埋めるだろうDoWork
、RunWorkerCompleted
と、ProgressChanged
イベントハンドラ。
それを非同期/待機に「変換」した場合は、次のようにします。
IProgress<int> progress = new Progress<int>();
progress.ProgressChanged += ( s, e ) =>
{
// TODO: do something with e.ProgressPercentage
// like update progress bar
};
await Task.Factory.StartNew(() =>
{
int i = 0;
// simulate lengthy operation
Stopwatch sw = Stopwatch.StartNew();
while (sw.Elapsed.TotalSeconds < 1)
{
if ((sw.Elapsed.TotalMilliseconds%100) == 0)
{
progress.Report((int) (1000 / sw.ElapsedMilliseconds))
}
++i;
}
});
// TODO: do something on the UI thread, like
// update status or display "result"
コンポーネントをデザイナーサーフェイスにドラッグする機能がない場合、どちらが「より良い」かを判断するのはリーダー次第です。しかし、それは私にとって、との比較でawait
ありBackgroundWorker
、のような組み込みメソッドを待つことができるかどうかではありませんStream.ReadAsync
。たとえば、BackgroundWorker
意図したとおりに使用している場合は、に変換するのが難しい場合がありますawait
。
その他の考え:http : //jeremybytes.blogspot.ca/2012/05/backgroundworker-component-im-not-dead.html
var t1 = webReq.GetResponseAsync(); var t2 = webReq2.GetResponseAsync(); await t1; await t2;
。2つの並列操作を待ちます。Awaitは非同期ではるかに優れていますが、シーケンシャルタスク、IMO ...
await Task.WhenAny(t1, t2)
どちらかのタスクが最初に完了したときに何かを行うために使用できます。他のタスクも確実に完了するためのループが必要になる可能性があります。通常は、特定のタスクがいつ完了するかを知りたいため、シーケンシャルを記述しawait
ます。
これは良い導入です:http : //msdn.microsoft.com/en-us/library/hh191443.aspx スレッドセクションはあなたが探しているものです:
非同期メソッドは、非ブロッキング操作を目的としています。非同期メソッドのawait式は、待機中のタスクの実行中に現在のスレッドをブロックしません。代わりに、式は継続としてメソッドの残りの部分にサインアップし、asyncメソッドの呼び出し元に制御を返します。
asyncおよびawaitキーワードを使用しても、追加のスレッドが作成されることはありません。非同期メソッドは独自のスレッドで実行されないため、非同期メソッドはマルチスレッドを必要としません。メソッドは現在の同期コンテキストで実行され、メソッドがアクティブな場合にのみスレッドで時間を使用します。Task.Runを使用してCPUにバインドされた作業をバックグラウンドスレッドに移動できますが、バックグラウンドスレッドは、結果が利用可能になるのを待っているだけのプロセスには役立ちません。
非同期プログラミングへの非同期ベースのアプローチは、ほとんどすべての場合で既存のアプローチよりも望ましい方法です。特に、このアプローチは、コードが単純であり、競合状態から保護する必要がないため、IOバウンド操作のBackgroundWorkerよりも優れています。Task.Runがスレッドプールに転送する作業からコードの実行の調整の詳細を分離するため、Task.Runと組み合わせて、非同期プログラミングはCPUにバインドされた操作のBackgroundWorkerよりも優れています。
BackgroundWorkerは、.NET 4.5では廃止されたものとして明示的にラベル付けされています。
MSDNの記事「非同期と待機を使用した非同期プログラミング(C#およびVisual Basic)」では、次のように説明しています。
非同期プログラミングへの非同期ベースのアプローチは、ほとんどすべての場合で既存のアプローチよりも望ましい方法です。特に、このアプローチは 、コードが単純であり、競合状態から保護する必要がないため、IOバウンド操作のBackgroundWorker よりも優れています。Task.Runと組み合わせて、非同期プログラミングは、CPUにバインドされた操作のBackgroundWorkerよりも優れています。非同期プログラミングは、コードの実行に関する調整の詳細を、Task.Runがスレッドプールに転送する作業から分離するためです。
更新
この質問は別の投稿として投稿されるべきでした。
ウィキペディアには、レース状況についての良い説明があります。その必要な部分はマルチスレッド化であり、同じMSDNの記事から非同期と待機を使用した非同期プログラミング(C#およびVisual Basic)からです。
非同期メソッドは、非ブロッキング操作を目的としています。非同期メソッドのawait式は、待機中のタスクの実行中に現在のスレッドをブロックしません。代わりに、式は継続としてメソッドの残りの部分にサインアップし、asyncメソッドの呼び出し元に制御を返します。
asyncおよびawaitキーワードを使用しても、追加のスレッドが作成されることはありません。非同期メソッドは独自のスレッドで実行されないため、非同期メソッドはマルチスレッドを必要としません。メソッドは現在の同期コンテキストで実行され、メソッドがアクティブな場合にのみスレッドで時間を使用します。Task.Runを使用してCPUにバインドされた作業をバックグラウンドスレッドに移動できますが、バックグラウンドスレッドは、結果が利用可能になるのを待っているだけのプロセスには役立ちません。
非同期プログラミングへの非同期ベースのアプローチは、ほとんどすべての場合で既存のアプローチよりも望ましい方法です。特に、このアプローチは、コードが単純であり、競合状態から保護する必要がないため、IOバウンド操作のBackgroundWorkerよりも優れています。Task.Runと組み合わせて、非同期プログラミングは、CPUにバインドされた操作のBackgroundWorkerよりも優れています。非同期プログラミングは、コードの実行に関する調整の詳細を、Task.Runがスレッドプールに転送する作業から分離するためです。
つまり、「asyncキーワードとawaitキーワードによって追加のスレッドが作成されることはありません」。
私が1年前にこの記事を研究していたときの自分の試みを思い出すことができる限り、同じ記事のコードサンプルを実行して遊んだ場合、非同期バージョンではない状況にぶつかることがあります(変換しようとすることができます)それを自分に)無期限にブロック!
また、具体的な例については、このサイトを検索できます。ここにいくつかの例があります: