Esto es probable TL; DR para muchos, pero creo que comparar await
con BackgroundWorker
es como comparar manzanas y naranjas y mis pensamientos sobre esto son los siguientes:
BackgroundWorker
está destinado a modelar una única tarea que desea realizar en segundo plano, en un subproceso de grupo de subprocesos. async
/ await
es una sintaxis para esperar asincrónicamente operaciones asincrónicas. Esas operaciones pueden o no usar un subproceso de grupo de subprocesos o incluso usar cualquier otro subproceso . Entonces, son manzanas y naranjas.
Por ejemplo, puede hacer algo como lo siguiente con await
:
using (WebResponse response = await webReq.GetResponseAsync())
{
using (Stream responseStream = response.GetResponseStream())
{
int bytesRead = await responseStream.ReadAsync(buffer, 0, buffer.Length);
}
}
Pero, probablemente nunca modelarías eso en un trabajador en segundo plano, probablemente harías algo como esto en .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 la desunión de la eliminación en comparación entre las dos sintaxis y cómo no puede usar using
sinasync
/ await
.
Pero, no harías algo así con eso BackgroundWorker
. BackgroundWorker
Por lo general, es para modelar una sola operación de larga duración que no desea afectar la capacidad de respuesta de la interfaz de usuario. Por ejemplo:
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();
Realmente no hay nada allí con lo que pueda usar async / wait, BackgroundWorker
está creando el hilo para usted.
Ahora, podría usar TPL en su lugar:
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);
En cuyo caso, TaskScheduler
está creando el hilo para usted (asumiendo el valor predeterminado TaskScheduler
), y podría usar await
lo siguiente:
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"
En mi opinión, una comparación importante es si estás informando progreso o no. Por ejemplo, puede tener BackgroundWorker like
esto:
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();
Pero no se ocuparía de algo de esto porque arrastraría y soltaría el componente de trabajador de fondo en la superficie de diseño de un formulario, algo que no puede hacer con async
/ await
y Task
... es decir, ganó ' t cree manualmente el objeto, establezca las propiedades y configure los controladores de eventos. solo llenarías el cuerpo de la DoWork
,RunWorkerCompleted
y ProgressChanged
los controladores de eventos.
Si "convertiste" eso en asíncrono / espera, harías 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"
Sin la capacidad de arrastrar un componente a una superficie de diseñador, realmente depende del lector decidir cuál es "mejor". Pero, para mí, esa es la comparación entre await
y BackgroundWorker
no si puedes esperar métodos incorporados como Stream.ReadAsync
. por ejemplo, si estaba usando BackgroundWorker
según lo previsto, podría ser difícil de convertir para usar await
.
Otros pensamientos: http://jeremybytes.blogspot.ca/2012/05/backgroundworker-component-im-not-dead.html