Это, вероятно, 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 / 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обработчики событий.
Если бы вы «преобразовали» это в async / await, вы бы сделали что-то вроде:
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