2011-09-28 13 views
11

Ho un codice molto simile quando utilizzo i metodi BeginRead e EndRead standard dal TcpClient e utilizzo di Task.Factory.FromAsync.La differenza tra Task.Factory.FromAsync e BeginX/EndX?

Ecco alcuni esempi. Codice di gestione degli errori non mostrato.

Task.Factory.FromAsync:

private void Read(State state) 
{ 
    Task<int> read = Task<int>.Factory.FromAsync(state.Stream.BeginRead, state.Stream.EndRead, state.Bytes, state.BytesRead, state.Bytes.Length - state.BytesRead, state, TaskCreationOptions.AttachedToParent); 

    read.ContinueWith(FinishRead); 
} 

private void FinishRead(Task<int> read) 
{ 
    State state = (State)read.AsyncState; 

    state.BytesRead += read.Result; 
} 

utilizzo standard di callback con BeginRead e EndRead:

private void Read(State state) 
{ 
    client.BeginRead(state.Bytes, state.BytesRead, state.Bytes.Length - state.Bytes.Read, FinishRead, state); 
} 

private void FinishRead(IAsyncResult async) 
{ 
    State state = (State)async.AsyncState; 

    state.BytesRead += state.Stream.EndRead(async); 
} 

Entrambi questi funzionano bene, ma sono curioso di loro differenze. Le linee di codice per entrambi sono praticamente equivalenti ed entrambe sembrano eseguire esattamente la stessa funzione e avere la stessa efficienza. Quale è preferibile? Cosa preferiresti vedere nel codice di produzione?

risposta

14

Avrei preferito vedere Task<T> codice basato:

  • Esso prevede la composizione più facilmente; ad esempio, è ragionevolmente facile scrivere un metodo che accetta una raccolta di attività Task<T> e restituisce un'altra attività che rappresenta il verdetto di maggioranza di tali attività. Allo stesso modo è possibile attendere fino al completamento di una qualsiasi raccolta di attività, ecc.
  • Fornisce una pianificazione più flessibile di dove viene eseguita la continuazione.
  • Consente di restituire il compito con sicurezza del tipo e molte più informazioni rispetto al tipo un po 'anemico IAsyncResult restituito da BeginRead.
  • È più semplice specificare la gestione degli errori e la cancellazione delle attività rispetto all'uso del modello Inizio/Fine.
  • Task<T> sta migliorando il supporto della lingua in C# 5 con async/attendono - se il codebase utilizza già Task<T> pervasivamente, sarà molto più facile approfittare di questa

In sostanza nel codice moderno in esecuzione su .NET 4, Task<T> è il modo idiomatico di rappresentare un'attività in corso. È un ambiente molto più ricco di lavoro rispetto ai tentativi precedenti, e lo abbraccerei se ne avessi la possibilità. Ovviamente se si sta utilizzando .NET 3.5 o versioni precedenti, la vita è un po 'più difficile, ma sto supponendo che, come si sta ponendo la domanda, Task<T> è un'opzione ...

+1

Grazie per la risposta! Sono ancora un po 'confuso però. So che BeginRead è molto efficiente perché la callback utilizza una porta di completamento dell'IO anziché il blocco. ContineWith è la stessa in termini di efficienza in quanto non blocca e funziona solo nello stesso momento in cui EndRead sarebbe stato eseguito? Inoltre, potresti approfondire come supporta la migliore gestione degli errori? Non dovrei anche fare lo stesso try-catch su entrambe le righe 'state.BytesRead + =' in ogni esempio di codice? –

+2

@RyanPeschel: Sì, non blocca, altrimenti sarebbe inutile. E no, non avresti bisogno dello stesso try/catch, perché potresti specificare una continuazione da eseguire su errore, un'altra da eseguire su cancellazione e un'altra da eseguire in caso di successo - guarda i sovraccarichi di ContinueWith. È anche possibile * testare * lo stato di un'attività senza solo cercare di ottenere il risultato (guarda su Task.Status). Il tutto è molto più ricco, in pratica. E il supporto asincrono in C# 5 è meraviglioso. –

+0

Sto controllando i sovraccarichi ma non sto proprio vedendo cosa stai ricevendo. Come posso specificare un metodo da eseguire quando c'è un errore/cancellazione? –