Estoy tratando de comprender mejor las opciones Async y Parallel que tengo en C#. En los fragmentos a continuación, he incluido los 5 enfoques con los que me encuentro más. Pero no estoy seguro de cuál elegir - o mejor aún, ¿qué criterios a considerar al elegir:C# Opciones asincrónicas para procesar una lista
Método 1: Tarea
(ver http://msdn.microsoft.com/en-us/library/dd321439.aspx)
Calling StartNew es funcionalmente equivalente para crear una tarea utilizando uno de sus constructores y luego llamar a Start para programarlo para su ejecución. Sin embargo, a menos que la creación y la programación deban separarse, StartNew es el enfoque recomendado tanto para la simplicidad como para el rendimiento.
método StartNew de TaskFactory debe ser el mecanismo preferido para la creación y la programación de las tareas de cálculo, pero para escenarios en los que la creación y la programación deben ser separados, los constructores pueden ser utilizados, y el método de inicio de la tarea pueden usarse entonces para programar la tarea para la ejecución en un momento posterior.
// using System.Threading.Tasks.Task.Factory
void Do_1()
{
var _List = GetList();
_List.ForEach(i => Task.Factory.StartNew(_ => { DoSomething(i); }));
}
Método 2: QueueUserWorkItem
(ver http://msdn.microsoft.com/en-us/library/system.threading.threadpool.getmaxthreads.aspx)
Puede poner en cola tantas solicitudes grupo de subprocesos como memoria del sistema permite. Si hay más solicitudes que subprocesos de grupo de subprocesos, las solicitudes adicionales permanecen en cola hasta que los subprocesos del grupo de subprocesos estén disponibles.
Puede colocar los datos requeridos por el método de la cola en los campos de instancia de la clase en la que se define el método, o puede utilizar la sobrecarga de QueueUserWorkItem (WaitCallback, objetos) que acepta un objeto que contiene los datos necesarios.
// using System.Threading.ThreadPool
void Do_2()
{
var _List = GetList();
var _Action = new WaitCallback((o) => { DoSomething(o); });
_List.ForEach(x => ThreadPool.QueueUserWorkItem(_Action));
}
Método 3: Parallel.Foreach
(ver: http://msdn.microsoft.com/en-us/library/system.threading.tasks.parallel.foreach.aspx)
La clase paralelo proporciona datos basados en bibliotecas reemplazos paralelas para operaciones comunes como para bucles, para cada bucle, y ejecución de un conjunto de instrucciones.
El cuerpo delegado se invoca una vez para cada elemento en la fuente enumerable. Se proporciona con el elemento actual como parámetro.
// using System.Threading.Tasks.Parallel
void Do_3()
{
var _List = GetList();
var _Action = new Action<object>((o) => { DoSomething(o); });
Parallel.ForEach(_List, _Action);
}
Método 4: IAsync.BeginInvoke
(ver: http://msdn.microsoft.com/en-us/library/cc190824.aspx)
BeginInvoke es asíncrona; por lo tanto, el control vuelve inmediatamente al objeto que llama después de que se invoca.
// using IAsync.BeginInvoke()
void Do_4()
{
var _List = GetList();
var _Action = new Action<object>((o) => { DoSomething(o); });
_List.ForEach(x => _Action.BeginInvoke(x, null, null));
}
Método 5: BackgroundWorker
(ver: http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.aspx)
Para configurar para una operación de fondo, añadir un controlador de eventos para el evento DoWork. Llame a su operación que consume mucho tiempo en este controlador de eventos. Para iniciar la operación, llame a RunWorkerAsync. Para recibir notificaciones de actualizaciones de progreso, gestione el evento ProgressChanged. Para recibir una notificación cuando se complete la operación, maneje el evento RunWorkerCompleted.
// using System.ComponentModel.BackgroundWorker
void Do_5()
{
var _List = GetList();
using (BackgroundWorker _Worker = new BackgroundWorker())
{
_Worker.DoWork += (s, arg) =>
{
arg.Result = arg.Argument;
DoSomething(arg.Argument);
};
_Worker.RunWorkerCompleted += (s, arg) =>
{
_List.Remove(arg.Result);
if (_List.Any())
_Worker.RunWorkerAsync(_List[0]);
};
if (_List.Any())
_Worker.RunWorkerAsync(_List[0]);
}
}
supongo que el critieria obvias serían:
- es mejor que el otro para el rendimiento?
- ¿Hay alguna mejor que la otra para el manejo de errores?
- ¿Hay alguna mejor que la otra para monitoreo/retroalimentación?
Pero, ¿cómo usted elige? Gracias de antemano por sus ideas.
También puede consultar System.Reactive (extensiones reactivas o rx.net). – lbergnehr
¡Y ni siquiera tocó el CTP Async! :-) – xanatos
Eso es cierto, pero me estaba apegando a C# 4. Buen punto, sin embargo. –