Ini mungkin TL; DR bagi banyak orang, tetapi, saya pikir membandingkan await
denganBackgroundWorker
seperti membandingkan apel dan jeruk dan pemikiran saya tentang hal berikut:
BackgroundWorker
dimaksudkan untuk memodelkan satu tugas yang ingin Anda lakukan di latar belakang, pada utas kumpulan utas. async
/ await
adalah 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 using
tanpa async
/ await
.
Tetapi, Anda tidak akan melakukan hal seperti itu dengan BackgroundWorker
. BackgroundWorker
biasanya 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, BackgroundWorker
membuat 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 TaskScheduler
ini membuat utas untuk Anda (dengan asumsi default TaskScheduler
), dan dapat digunakan await
sebagai 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 like
ini:
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
/ await
dan Task
... yaitu Anda menang ' t secara manual membuat objek, mengatur properti dan mengatur event handler. Anda hanya akan mengisi tubuh DoWork
, RunWorkerCompleted
danProgressChanged
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 await
dan BackgroundWorker
, bukan apakah Anda bisa menunggu metode bawaan seperti Stream.ReadAsync
. mis. jika Anda menggunakan BackgroundWorker
sebagaimana dimaksud, mungkin sulit untuk mengkonversi untuk digunakanawait
.
Pikiran lain: http://jeremybytes.blogspot.ca/2012/05/backgroundworker-component-im-not-dead.html