11

Ho un metodo di questo tipo di ritorno:Come concatenare enumerables asincroni?

public async Task<IEnumerable<T>> GetAll() 

Rende alcuni ulteriori chiamate asincrone (numero imprecisato) ognuno dei quali restituiscono un compito di T enumerabile, e quindi vuole concat i risultati per il ritorno.

var data1 = src1.GetAll(); 
var data2 = src2.GetAll(); 
var data3 = src3.GetAll(); //and so on 

Ora è abbastanza facile per attendere tutti e concat i risultati per produrre il singolo enumerabile, ma mi piacerebbe l'enumerabile di essere disponibile non appena le prime dichiarazioni di chiamata, con i potenziali attese per il chiamante/enumeratore se qualche chiamata è ancora in sospeso quando i risultati disponibili sono esauriti.

Devo eseguire manualmente un concat a mano per questo, aggirando la mancanza di supporto dell'enumeratore quando è racchiuso in un'attività <>? Oppure c'è già una chiamata alla biblioteca in TPL o altrove che potrebbe aiutarmi. Ho dato un'occhiata a IX, ma è ancora in versione sperimentale e non voglio piegarlo.

Su una nota a margine, è quello che sto cercando un anti-pattern? Posso pensare a una complicazione, gestione delle eccezioni - dal lato del chiamante, la chiamata può essere completata con successo e inizia a utilizzare l'enumerabile ma può esplodere a metà strada ...

+0

(Come nota a margine) Il motivo sembra essere asimmetrico: il codice _ attende che la prima sequenza sia pronta, ma non aspetta il resto. – Vlad

+5

Forse hai davvero bisogno di 'IObservable '? In questo caso potresti semplicemente usare ['Observable.Concat'] (https://msdn.microsoft.com/en-us/library/system.reactive.linq.observable.concat%28v=vs.103%29.aspx). – Vlad

+0

@Vlad: buon punto. Ho pensato a questo quando ho esaminato Ix/Rx e sono d'accordo, reattivo tende ad adattarsi meglio a questo tipo di caso d'uso. Ma lo scenario generale e l'applicazione sono basati su pull e non voglio cadere nel martello Rx solo per tornare agli enumerabili dal risultato osservabile. – Vivek

risposta

6

Esiste un progetto esistente chiamato Async Enumerable che risponde questo problema esattamente

È possibile utilizzarlo facilmente.

Ad esempio:

IAsyncEnumerable<string> GetAsyncAnswers() 
{ 
    return AsyncEnum.Enumerate<string>(async consumer => 
    { 
     foreach (var question in GetQuestions()) 
     { 
      string theAnswer = await answeringService.GetAnswer(question); 
      await consumer.YieldAsync(theAnswer); 
     } 
    }); 
} 

Questo espone un IAsyncEnumerable<string> da cui si ricava una volta GetAnswer rendimenti. È possibile esporre internamente un IAsyncEnumerable<T> nel proprio caso e effettuare internamente chiamate all'interno di GetAll.

cosa sto cercando un anti-pattern? Mi viene in mente una complicazione, la gestione delle eccezioni - dal lato del chiamante, la chiamata può completare con successo e lui inizia a utilizzare l'enumerabile ma può far saltare in aria metà che ...

non lo farei dillo Questo ha potenzialmente problemi come un'eccezione che si verifica internamente durante una delle attese, ma questo potrebbe anche potenzialmente verificarsi all'interno di qualsiasi IEnumerable<T>. Le sequenze asincrone sono qualcosa di necessario nella realtà odierna delle API asincrone emergenti.

+1

Grazie. Contrassegnato come risposta. Non ho importato la libreria, ma ho terminato eseguendo il mio proprio in ogni caso in due linee simili al tuo campione, tramite un concatenatore che ha una funzione per ottenere la successiva enumerabile. Forse darò un'altra occhiata alla biblioteca se avrò un caso d'uso più ampio. – Vivek