Ini mungkin TL; DR bagi banyak orang, tetapi, saya pikir membandingkan awaitdenganBackgroundWorker seperti membandingkan apel dan jeruk dan pemikiran saya tentang hal berikut:
BackgroundWorkerdimaksudkan untuk memodelkan satu tugas yang ingin Anda lakukan di latar belakang, pada utas kumpulan utas. async/ awaitadalah sintaks untuk menunggu secara tidak sinkron pada operasi asinkron. Operasi-operasi itu mungkin atau mungkin tidak menggunakan thread pool thread atau bahkan menggunakan utas lainnya . Jadi, mereka adalah apel dan jeruk.
Misalnya, Anda dapat melakukan sesuatu seperti berikut ini dengan await:
using (WebResponse response = await webReq.GetResponseAsync())
{
using (Stream responseStream = response.GetResponseStream())
{
int bytesRead = await responseStream.ReadAsync(buffer, 0, buffer.Length);
}
}
Tapi, Anda mungkin tidak akan pernah memodelkan hal itu di latar belakang pekerja, Anda mungkin akan melakukan sesuatu seperti ini di .NET 4.0 (sebelum 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);
Perhatikan perbedaan pemisahan antara kedua sintaks dan bagaimana Anda tidak dapat menggunakan usingtanpa async/ await.
Tetapi, Anda tidak akan melakukan hal seperti itu dengan BackgroundWorker. BackgroundWorkerbiasanya untuk memodelkan operasi jangka panjang tunggal yang Anda tidak ingin memengaruhi respons UI. Sebagai contoh:
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();
Benar-benar tidak ada di sana Anda dapat menggunakan async / tunggu, BackgroundWorkermembuat utas untuk Anda.
Sekarang, Anda bisa menggunakan TPL sebagai gantinya:
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);
Dalam hal TaskSchedulerini membuat utas untuk Anda (dengan asumsi default TaskScheduler), dan dapat digunakan awaitsebagai berikut:
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"
Menurut pendapat saya, perbandingan utama adalah apakah Anda melaporkan kemajuan atau tidak. Misalnya, Anda mungkin memiliki BackgroundWorker likeini:
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();
Tapi, Anda tidak akan berurusan dengan beberapa hal ini karena Anda akan menyeret-dan-menjatuhkan komponen pekerja latar belakang ke permukaan desain formulir - sesuatu yang tidak dapat Anda lakukan dengan async/ awaitdan Task... yaitu Anda menang ' t secara manual membuat objek, mengatur properti dan mengatur event handler. Anda hanya akan mengisi tubuh DoWork, RunWorkerCompleteddanProgressChanged event handler.
Jika "dikonversi" menjadi async / menunggu, Anda akan melakukan sesuatu seperti:
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"
Tanpa kemampuan untuk menyeret komponen ke permukaan Designer, terserah pembaca untuk memutuskan mana yang "lebih baik". Tapi, bagi saya, itu adalah perbandingan antara awaitdan BackgroundWorker, bukan apakah Anda bisa menunggu metode bawaan seperti Stream.ReadAsync. mis. jika Anda menggunakan BackgroundWorkersebagaimana dimaksud, mungkin sulit untuk mengkonversi untuk digunakanawait .
Pikiran lain: http://jeremybytes.blogspot.ca/2012/05/backgroundworker-component-im-not-dead.html