É provável que TL; DR para muitos, mas acho que comparar await
com BackgroundWorker
é como comparar maçãs e laranjas e meus pensamentos sobre isso a seguir:
BackgroundWorker
destina-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 using
sem async
/ await
.
Mas você não faria algo assim com BackgroundWorker
. BackgroundWorker
geralmente é 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 BackgroundWorker
esteja 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 TaskScheduler
está criando o encadeamento para você (assumindo o padrão TaskScheduler
) e pode ser usado da await
seguinte 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 like
isso:
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
/ await
e 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
, RunWorkerCompleted
e ProgressChanged
manipuladores 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 await
e BackgroundWorker
, não se você pode aguardar métodos internos como Stream.ReadAsync
. por exemplo, se você estiver usando BackgroundWorker
como pretendido, pode ser difícil converter para usar await
.
Outras opiniões: http://jeremybytes.blogspot.ca/2012/05/backgroundworker-component-im-not-dead.html