Diferencia entre delegado.BeginInvoke y usando hilos ThreadPool en C#


En C# hay alguna diferencia entre usar un delegado para hacer algún trabajo de forma asíncrona (llamando a BeginInvoke()) y usar un subproceso ThreadPool como se muestra a continuación

public void asynchronousWork(object num)
    {
        //asynchronous work to be done
        Console.WriteLine(num);
    }

 public void test()
    {
        Action<object> myCustomDelegate = this.asynchronousWork;
        int x = 7;

        //Using Delegate
        myCustomDelegate.BeginInvoke(7, null, null);

        //Using Threadpool
        ThreadPool.QueueUserWorkItem(new WaitCallback(asynchronousWork), 7);
        Thread.Sleep(2000);
    }

Editar:
BeginInvoke se asegura de que se use un subproceso del grupo de subprocesos para ejecutar el código asincrónico, ¿hay alguna diferencia?

Author: Jason Down, 2012-04-27

1 answers

Joe Duffy, en su Concurrent Programming on Windows libro (página 418), dice esto acerca de Delegate.BeginInvoke:

Todos los tipos de delegados, por convención, ofrecen un método BeginInvoke y EndInvoke junto con el método ordinario síncrono Invoke. Si bien esta es una buena característica del modelo de programación, debe mantenerse alejado de ellos siempre que sea posible. La implementación utiliza una infraestructura remota que impone una sobrecarga considerable a la invocación asincrónica. Cola de trabajo al grupo de subprocesos directamente es a menudo un mejor enfoque, aunque eso significa que tienes que coordinar la lógica del encuentro tú mismo.

EDITAR: He creado la siguiente prueba simple de los gastos generales relativos:

int counter = 0;
int iterations = 1000000;
Action d = () => { Interlocked.Increment(ref counter); };

var stopwatch = new System.Diagnostics.Stopwatch();
stopwatch.Start();
for (int i = 0; i < iterations; i++)
{
    var asyncResult = d.BeginInvoke(null, null);
}

do { } while(counter < iterations);
stopwatch.Stop();

Console.WriteLine("Took {0}ms", stopwatch.ElapsedMilliseconds);
Console.ReadLine();

En mi máquina la prueba anterior se ejecuta en alrededor de 20 segundos. Sustitución de la llamada BeginInvoke por

System.Threading.ThreadPool.QueueUserWorkItem(state =>
{
    Interlocked.Increment(ref counter);
});

Cambia el tiempo de ejecución a 864ms.

 32
Author: Lee,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-04-26 22:34:03