2010-09-14 7 views
5

Attualmente ho una sezione di codice che deve fare circa 7 chiamate di servizi Web a vari fornitori per i dati. Ogni chiamata richiede diversi secondi per essere eseguita, quindi mi piacerebbe eseguirli in parallelo per velocizzare le cose.Utilizzo di .Net Parallel Extensions (Parallel.Invoke) per più chiamate asincrone?

Ho avvolto le mie 7 chiamate in un Parallel.Invoke che funziona alla grande con un paio di cose allo stesso tempo, ma su un server 2 core, eseguirà solo 2 alla volta, una per core. Dato che tutto quello che sto facendo è aspettare che le chiamate al servizio web tornino, vorrei che andassero a prendere tutte le 7 e aspettiamo che ritornino.

Non c'è un modo per fare questo? O forse il mio approccio è sbagliato? Forse ho bisogno di creare chiamate asincrone ai servizi web? Ma poi come aspettare che tornino tutti prima di andare avanti?

risposta

5

ma su un server di 2 conduttori, sarà eseguire solo 2 alla volta, uno per core

mi chiedo questo - Parallel.Invoke in genere eseguire molte più attività di core nel vostro sistema .

Detto questo, se si utilizzano chiamate di chiamate al metodo asincrone, si consiglia di utilizzare Task.Factory.FromAsync(...) per generare le sette attività distinte.

Questo fornisce la flessibilità di fare altri lavori, mentre i compiti eseguiti, quindi chiamando Task.WaitAll (o Task.WaitAny) quando si decide di utilizzare i risultati.

Parallel.Invoke, d'altra parte, sarà sempre bloccare fino a quando tutti e sette completa.

+2

Ho avuto l'impressione che volesse che tutti fossero completati prima di continuare. –

+1

@Steven: che può fare tramite Task.WaitAll - ma può fare altro lavoro mentre sta aspettando, se è disponibile, se è un'opzione. Casi come questo, però, spesso funzionano con Task.WaitAny, dato che di solito puoi iniziare alcuni dei lavori non appena alcune delle attività sono completate - è raro che siano necessari 7 risultati diversi per eseguire qualsiasi elaborazione ... –

+0

Sei bene, funzionerà anche questo, e in modo più flessibile di quello che ho suggerito. –

0

È possibile specificare ParallelOptions per aumentare il livello di concorrenza. L'impostazione predefinita è ragionevole per i task associati alla CPU, ma hai a che fare con quelli con I/O, quindi ha senso sovrascrivere quel comportamento.

+0

Ho pensato che l'aumento del livello di concorrenza si estende solo fino alla massima concorrenza consentita? cioè se hai 8 core, puoi impostare il livello di concorrenza su qualsiasi cosa..ma andando più in alto di 8 non farai nulla ... – puffpio

+0

@puffpio: tutto ciò che dice è: "MaxDegreeOfParallelism limita il numero di operazioni simultanee eseguite da chiamate di metodo Parallelo che passano questa istanza di ParallelOptions al valore impostato, se è positivo.Se MaxDegreeOfParallelism è -1, allora non c'è limite posto sul numero di operazioni in esecuzione contemporaneamente. " –

+0

Sì, questo mi confonde, poiché dice "limite" che per me significa che non andrà oltre il numero di core che hai. Dico questo perché la pagina su Parallel.Invoke dice: "Notare che con Invoke(), si esprimono semplicemente quali azioni si desidera eseguire contemporaneamente, e il runtime gestisce tutti i dettagli di scheduling, incluso il ridimensionamento automatico al numero di core sul computer ospite." – puffpio

1

Non c'è alcuna reale necessità di utilizzare Parallel.Invoke per questo. È possibile procedere e inviare più richieste asincrone (ad esempio HttpWebRequest.BeginGetResponse()). Per quanto riguarda la notifica al completamento, sono disponibili diverse opzioni. Un modo semplice sarebbe quello di inizializzare uno CountdownEvent prima di emettere la prima richiesta, e quindi fare in modo che il thread principale aspetti su quell'evento dopo che ha emesso le richieste. I metodi di callback asincroni segnalano ciascun evento al loro completamento. In questo modo, ti assicuri che tutte le richieste siano state completate prima che il tuo thread principale continui.

+1

Ma TPL è molto più facile dell'APM. Sarebbe bello se potessimo avere il meglio di entrambi i mondi. –

+0

Utilizzo di Task.Factory.StartAsync offre il meglio di entrambi i mondi ... senza la necessità di tenere traccia di CountdownEvent, ecc. –

+0

Ho bisogno di guardare più da vicino la TPL. –

0

ho intenzione di copiare a response that I made to another question testualmente perché è altrettanto, se non di più, applicabile qui.


Non si può battere il modello di programmazione asincrono (APM) quando si tratta di prestazioni I/O. Ogni volta che puoi usarlo, dovresti esserlo. Fortunatamente la Task Parallel Library (TPL) viene fornita con il supporto per combinare il lavoro APM nel mix con attività TPL "pure" tramite the FromAsync factory method.

Consulta questa sezione di .NET SDK su MSDN dal titolo TPL and Traditional .NET Asynchronous Programming per ulteriori informazioni su come combinare questi due modelli di programmazione per ottenere il nirvana asincrono.