Это, вероятно, 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