Pregunta

Generalmente desconfío de implementar interfaces parcialmente. Sin embargo, IAsyncResult es un caso un poco especial, dado que admite varios patrones de uso bastante diferentes. ¿Con qué frecuencia usa / ve el patrón AsyncState / AsyncCallback , en lugar de simplemente llamar a EndInvoke , usando AsyncWaitHandle o sondeo IsCompleted (yuck)?

Pregunta relacionada: Detectando que un ThreadPool WorkItem tiene completado / en espera de finalización .

Considere esta clase (muy aproximada, se necesita bloqueo):

public class Concurrent<T> {
    private ManualResetEvent _resetEvent;
    private T _result;

    public Concurrent(Func<T> f) {
        ThreadPool.QueueUserWorkItem(_ => {
                                         _result = f();
                                         IsCompleted = true;
                                         if (_resetEvent != null)
                                             _resetEvent.Set();
                                     });
    }

    public WaitHandle WaitHandle {
        get {
            if (_resetEvent == null)
                _resetEvent = new ManualResetEvent(IsCompleted);
            return _resetEvent;
        }

    public bool IsCompleted {get; private set;}
    ...

Tiene WaitHandle (creado perezosamente, tal como se describe en la documentación de IAsyncResult ) y IsCompleted , pero no veo una implementación sensata para AsyncState ( {return null;} ?). Entonces, ¿tiene sentido implementar IAsyncResult ? Tenga en cuenta que Task en la biblioteca Parallel Extensions implementa IAsyncResult , pero solo IsCompleted se implementa implícitamente.

¿Fue útil?

Solución

  • En mi experiencia, simplemente llamar a EndInvoke sin esperar ni ser llamado primero rara vez es útil
  • Simplemente proporcionar devoluciones de llamada a veces no es suficiente, ya que sus clientes pueden querer esperar varias operaciones a la vez (WaitAny, WaitAll)
  • Nunca he encuestado IsCompleted, ¡qué asco! Por lo tanto, podría guardar la implementación de IsCompleted, pero es tan simple que no parece que valga la pena sorprender a sus clientes.

Entonces, una implementación razonable para un método invocable asincrónicamente debería proporcionar un IAsyncResult completamente implementado.

Por cierto, a menudo no necesita implementar IAsyncResult usted mismo, solo devuelva lo que Delegate.BeginInvoke devuelve. Consulte la implementación de System.IO.Stream.BeginRead para ver un ejemplo.

Otros consejos

Parece que tienes un par de preguntas. Vamos a manejarlos individualmente

Creando WaitHandle perezosamente

Sí, este es el enfoque más correcto. Debe hacer esto de una manera segura para subprocesos, pero perezoso es el camino.

El truco es deshacerse de WaitHandle. WaitHandle es una base de IDisposable y debe eliminarse de manera oportuna. La documentación de IAsycResult no cubre este caso. La mejor manera de hacerlo es en EndInvoke. La documentación de BeginInvoke establece explícitamente que para cada BeginInvoke, debe haber un EndInvoke correspondiente (o BeginRead / EndRead). Este es el mejor lugar para deshacerse de WaitHandle.

¿Cómo se debe implementar AsyncState?

Si observa las API BCL estándar que devuelven un IAsyncResult, la mayoría de ellas toman un parámetro de estado. Por lo general, este es el valor que devuelve AsyncState (consulte las API de Socket para ver un ejemplo). Es una buena práctica incluir una variable de estado escrita como objeto para cualquier API de estilo BeginInvoke de API que devuelva un IAsyncResult. No es necesario pero es una buena práctica.

En ausencia de una variable de estado, el retorno nulo es aceptable.

API IsCompleted

Esto dependerá en gran medida de la implementación que crea IAsyncResult. Pero sí, deberías implementarlo.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top