Domanda

Sono generalmente diffidente nell'implementare parzialmente le interfacce. Tuttavia, IAsyncResult è un po 'un caso speciale, dato che supporta diversi schemi di utilizzo abbastanza diversi. Con quale frequenza usi / vedi il modello AsyncState / AsyncCallback , invece di chiamare semplicemente EndInvoke , usando AsyncWaitHandle o polling IsCompleted (yuck)?

Domanda correlata: Rilevare che un ThreadPool WorkItem ha completato / in attesa di completamento .

Considera questa classe (molto approssimativa, blocco necessario):

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;}
    ...

Ha WaitHandle (creato pigramente, proprio come descritto nella documentazione IAsyncResult ) e IsCompleted , ma non vedo un'implementazione ragionevole per AsyncState ( {return null;} ?). Quindi ha senso implementare IAsyncResult ? Nota che Task nella libreria delle estensioni parallele implementa IAsyncResult , ma solo IsCompleted è implementato implicitamente.

È stato utile?

Soluzione

  • Nella mia esperienza, chiamare semplicemente EndInvoke senza aspettare o essere richiamato per primo è raramente utile
  • A volte non è sufficiente fornire solo callback, poiché i tuoi clienti potrebbero voler attendere più operazioni contemporaneamente (WaitAny, WaitAll)
  • Non ho mai eseguito il polling di IsCompleted, davvero schifo! Quindi, potresti salvare l'implementazione di IsCompleted, ma è così semplice che non sembra valga la pena stupire i tuoi clienti.

Quindi, un'implementazione ragionevole per un metodo richiamabile in modo asincrono dovrebbe davvero fornire un IAsyncResult completamente implementato.

A proposito, spesso non è necessario implementare IAsyncResult da soli, è sufficiente restituire ciò che viene restituito da Delegate.BeginInvoke. Vedi l'implementazione di System.IO.Stream.BeginRead per un esempio.

Altri suggerimenti

Sembra che tu abbia un paio di domande. Gestiamoli singolarmente

Creazione di WaitHandle pigramente

Sì, questo è l'approccio più corretto. Dovresti farlo in modo sicuro, ma pigro è il modo.

Il trucco però è eliminare WaitHandle. WaitHandle è una base di IDisposable e deve essere eliminato in modo tempestivo. La documentazione per IAsycResult non copre questo caso. Il modo migliore per farlo è in EndInvoke. La documentazione per BeginInvoke afferma esplicitamente che per ogni BeginInvoke deve esserci un EndInvoke corrispondente (o BeginRead / EndRead). Questo è il posto migliore in cui smaltire WaitHandle.

Come dovrebbe essere implementato AsyncState?

Se si guardano le API BCL standard che restituiscono un IAsyncResult, la maggior parte di esse accetta un parametro state. Questo è in genere il valore restituito da AsyncState (vedere le API Socket per un esempio). È buona norma includere una variabile di stato digitata come oggetto per qualsiasi API in stile BeginInvoke API che restituisce un IAsyncResult. Non necessaria ma buona pratica.

In assenza di una variabile di stato, è accettabile la restituzione di null.

API IsCompleted

Questo dipenderà fortemente dall'implementazione che crea IAsyncResult. Ma sì, dovresti implementarlo.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top