É provável que TL; DR para muitos, mas acho que comparar awaitcom BackgroundWorkeré como comparar maçãs e laranjas e meus pensamentos sobre isso a seguir:
BackgroundWorkerdestina-se a modelar uma única tarefa que você deseja executar em segundo plano, em um thread do conjunto de threads. async/ awaitÉ uma sintaxe para de forma assíncrona aguardando em operações assíncronas. Essas operações podem ou não usar um encadeamento de conjunto de encadeamentos ou até mesmo usar outro encadeamento . Então, são maçãs e laranjas.
Por exemplo, você pode fazer algo como o seguinte com await:
using (WebResponse response = await webReq.GetResponseAsync())
{
using (Stream responseStream = response.GetResponseStream())
{
int bytesRead = await responseStream.ReadAsync(buffer, 0, buffer.Length);
}
}
Mas, você provavelmente nunca modelaria isso em um trabalhador em segundo plano, provavelmente faria algo assim no .NET 4.0 (antes 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);
Observe a disjunção do descarte comparada entre as duas sintaxes e como você não pode usar usingsem async/ await.
Mas você não faria algo assim com BackgroundWorker. BackgroundWorkergeralmente é para modelar uma única operação de longa duração que você não deseja afetar a capacidade de resposta da interface do usuário. Por exemplo:
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();
Não há realmente nada lá com o qual você possa usar async / waitit BackgroundWorkeresteja criando o thread para você.
Agora, você pode usar o 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);
Nesse caso, o TaskSchedulerestá criando o encadeamento para você (assumindo o padrão TaskScheduler) e pode ser usado da awaitseguinte maneira:
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"
Na minha opinião, uma grande comparação é se você está relatando progresso ou não. Por exemplo, você pode ter BackgroundWorker likeisso:
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();
Mas você não lidaria com isso porque arrastaria e soltaria o componente de trabalho em segundo plano na superfície de design de um formulário - algo que não pode ser feito com async/ awaite Task... ou seja, você venceu ' t crie manualmente o objeto, defina as propriedades e os manipuladores de eventos. você só preencher o corpo dos DoWork, RunWorkerCompletede ProgressChangedmanipuladores de eventos.
Se você "converteu" isso em assíncrono / espera, faria algo como:
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"
Sem a capacidade de arrastar um componente para uma superfície do Designer, cabe ao leitor decidir qual é "melhor". Mas, para mim, essa é a comparação entre awaite BackgroundWorker, não se você pode aguardar métodos internos como Stream.ReadAsync. por exemplo, se você estiver usando BackgroundWorkercomo pretendido, pode ser difícil converter para usar await.
Outras opiniões: http://jeremybytes.blogspot.ca/2012/05/backgroundworker-component-im-not-dead.html