Це, мабуть, 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);
}
}
Але ви, ймовірно, ніколи не моделюватимете, що це фоновий працівник, ви, ймовірно, зробите щось подібне в .NET 4.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);
Зауважте нерозбірливість утилізації порівняно між двома синтаксисами та те, як ви не можете користуватися usingбез async/ await.
Але, ти б нічого подібного не робив BackgroundWorker. BackgroundWorkerзазвичай для моделювання однієї тривалої операції, на яку не хочеться впливати на чуйність інтерфейсу. Наприклад:
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 / ждати, 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