19

Gracias al buen trabajo de Jeremy Miller en Functional Programming For Everyday .NET Development, tengo un ejecutor de comandos que funciona y que hace todo lo que quiero (realizar trabajos pesados ​​en el grupo de subprocesos, enviar resultados o errores al contexto de sincronización e incluso registrar el progreso en el contexto de sincronización), pero no puedo explicar por qué usa SynchronizationContext.Send del grupo de subprocesos y Synchronization.Post del Func pasado al método que hace el trabajo pesado. He leído la documentación varias veces, pero no puedo entender lo que es la diferencia. ¿Qué se supone que obtengo del hecho de que uno se llama Send y se llama Post? Tengo la sensación de la magia está en el hecho de Send "inicia una sincrónica demanda" y Post "inicia una petición asíncrona ", pero ambas solicitudes proceden de la agrupación de hebras y necesitan ser enviados/enviados de vuelta al hilo de interfaz de usuario.¿Cuál es la diferencia entre SynchronizationContext.Send y SynchronizationContext.Post?

¿Alguien puede explicar la diferencia, incluso si se trata simplemente de un dispositivo mnemónico que me permite saber cuándo elegir uno sobre el otro?

En caso de que importa, este es mi código prueba donde uso Post para enviar el progreso de nuevo a la interfaz de usuario:

private Action _ExecuteCommand 
       (SynchronizationContext context 
       , Action<int, int> progress 
       , Action<int, int> after) 
{ 
    int count = 3; 
    int accumulatedValue = 0; 
    int threadId = Thread.CurrentThread.ManagedThreadId; 
    for (int i = 0; i < count; i++) 
    { 
     Thread.Sleep(1000); 
     context.Post(delegate { progress(i + 1, threadId); }); 
     accumulatedValue += i; 
    } 

    return() => after(threadId, accumulatedValue); 
} 

Eso _ExecuteCommand método se pasa como el parámetro command a continuación, en su mayoría de la artículo original, que utiliza para enviar Send finalización y el mensaje de error de nuevo a la interfaz de usuario:

public void Execute(Func<Action> command, Action<Exception> error) 
{ 
    ThreadPool.QueueUserWorkItem(o => 
    { 
     try 
     { 
      Action continuation = command(); 
      _Context.Send(s => continuation()); 
     } 
     catch (Exception e) 
     { 
      _Context.Send(s => error(e)); 
     } 
    }); 
} 
+4

Son métodos muy mal nombrados. –

Respuesta

23

enviar - sincrónica: esperar fo r respuesta (o acción completada)

Post - asíncrono: dejar y continuar

Así que su ejemplo se utilizan los métodos correctos en los momentos adecuados. No es necesario detener el bucle for hasta que se complete la actualización del progreso (por el contrario).
Y Execute desea esperar que se complete la Acción; de lo contrario, el manejo de excepciones no tiene ningún propósito.

+0

De modo que no se producen errores si uso Publicar en lugar de Enviar. Es solo cuestión de si necesito que la tarea del grupo de subprocesos se pause para que se envíe/publique el mensaje. ¿Derecha? – flipdoubt

+0

Sí, correcto .__ –

+2

Todavía estoy confundido por esto. Pensé que el contexto de sincronización te daba una forma fácil de trabajar en el hilo de la interfaz de usuario, así que ¿no tendrías que esperar? O funciona así: estás trabajando en un hilo de fondo y en el medio necesitas hacer algo de trabajo de IU y luego continuar con el hilo de fondo. Si usa Enviar, el hilo de fondo no continúa en la parte 2 hasta que termine el trabajo de IU. Sin embargo, si utiliza Publicar, el hilo de fondo continuará funcionando sin esperar a que funcione el hilo de IU. –

Cuestiones relacionadas