ThreadPool.QueueUserWorkItem con expresión lambda y método anónimo


Pasar dos parámetros a un nuevo hilo en el threadpool a veces puede ser complicado, pero parece que con expresiones lambda y métodos anónimos, puedo hacer esto:

public class TestClass
{
    public void DoWork(string s1, string s2)
    {
        Console.WriteLine(s1);
        Console.WriteLine(s2);
    }
}

try
{
    TestClass test = new TestClass();
    string s1 = "Hello";
    string s2 = "World";
    ThreadPool.QueueUserWorkItem(
        o => test.DoWork(s1, s2)
        );
}
catch (Exception ex)
{
    //exception logic
}

Ahora, ciertamente he simplificado este ejemplo, pero estos puntos son clave:

  • Los objetos string que se pasan son inmutables y, por lo tanto, threadsafe
  • Las variables s1 y s2 se declaran dentro del ámbito del bloque try, que salgo inmediatamente después de poner en cola el trabajo en el hilo pool, por lo que las variables s1 y s2 nunca se modifican después de eso.

¿Hay algo malo con esto?

La alternativa es crear una nueva clase que implemente un tipo inmutable con 3 miembros: test, s1 y s2. Eso parece un trabajo extra sin ningún beneficio en este momento.

Author: Scott Whitlock, 2009-04-10

5 answers

No hay nada malo en esto. El compilador está esencialmente haciendo automáticamente lo que usted describió como su alternativa. Crea una clase para contener las variables capturadas (test, s1 y s2) y pasa una instancia delegada a lambda que se convierte en un método en la clase anónima. En otras palabras, si siguieras adelante con tu alternativa terminarías con algo muy similar a lo que el compilador acaba de generar para ti.

 16
Author: chuckj,
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
2009-04-10 16:24:39

Para este ejemplo en particular, no no hay nada malo aquí. El estado que has pasado al otro hilo está completamente contenido y ninguno de los tipos involucrados tiene problemas de afinidad de hilo.

 4
Author: JaredPar,
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
2009-04-10 16:22:42

Es una buena manera de hacerlo. No veo ninguna desventaja de usar lambdas. Es simple y limpio.

 2
Author: Mehrdad Afshari,
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
2009-04-10 16:21:43

Lo que estás viendo se refiere como un cierre. Como chuckj afirma, el compilador está generando una clase en tiempo de compilación que corresponde a los miembros a los que se accede fuera del cierre.

Lo único de lo que tienes que preocuparte es si tienes parámetros ref o out. Mientras que las cadenas son inmutables, las referencias a ellas (o a cualquier variable) NO lo son.

 2
Author: casperOne,
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
2017-05-23 11:53:55

Un problema potencial con el patrón es que es muy tentador expandirlo en algo más genérico pero menos seguro como este (código scratch - no esperes que funcione):

public static void QueueTwoParameterWorkItem<T1, T2>(T1 value1, T2 value2, workDelegate<T1,T2> work)
{
    try
    {
        T1 param1 = value1;
        T2 param2 = value2;
        ThreadPool.QueueUserWorkItem(
            (o) =>
            {
                work(param1, param2);
            });
    }
    catch (Exception ex)
    {
        //exception logic
    }
}
 2
Author: Joel Coehoorn,
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
2009-04-10 21:18:25