2010-11-12 24 views
6

Ho bisogno di effettuare più chiamate asincrone da un servizio wcf ospitato in IIS (potrebbe essere rilevante, non lo so). Le chiamate sono ad altri servizi, ma li faccio inserendo una stringa nell'URL del servizio. Chiamarli in modo sincrono funziona, ma ho più di una dozzina di chiamate, e sono completamente indipendenti, quindi vorrei accelerarle chiamandole in modo asincrono.In attesa di più richieste POST asincrone

Ora, mi rendo conto che potrei semplicemente usare più thread per questo - e potrebbe essere la soluzione più semplice - ma ho pensato di provare async.

Il mio codice è simile a questo:

public delegate void Callback(string response); 

public static void InvokeAsync(string request, string url, Callback callback) 
    where TResponse: class 
{ 
    var web = new WebClient(); 
    web.Headers.Add("Content-Type", "application/x-www-form-urlencoded"); 

    web.UploadStringCompleted += (sender, e) => callback.Invoke(e.Result); 
    web.UploadStringAsync(new Uri(url), request); 
} 

//... 
var lockObj = new object(); 
foreach (var item in list) 
    InvokeAsync(item, url, response => { lock(lockObj) newList.Add(response); }); 

È possibile che questo dovrebbe funzionare, credo; tuttavia, il mio problema è che non ho idea di come aspettare fino a quando tutte le risposte sono tornate. Se utilizzo un contatore e attendo in un ciclo fino a quando non diventa zero, non ci sarà più alcuna CPU per gestire i callback. Lo stesso con l'utilizzo di qualche forma di semaforo, credo. C'è un modo non bloccante di aspettare finché non avrò recuperato tutte le risposte? (Modifica la firma del metodo di prendere anche una funzione di callback si muoverà solo il problema ad un livello superiore, temo.)

[Edit] Ecco una molto vicino domanda - How to invoke async operation as sync? - ma ho bisogno di aspettare multipla asincrona operazioni.

risposta

3

Per questo è necessario un AutoResetEvent.

provare il seguente per le ultime due righe:

var waitEvent = new AutoResetEvent(false); 

foreach (var item in list) 
    InvokeAsync(item, url, response => { lock(lockObj) newList.Add(response); waitEvent.Set(); }); 

while (newList.Count < list.Count) 
    waitEvent.WaitOne(); 

Tutti gli articoli devono essere completati quando newList contiene le voci che list. Quando arriva un nuovo elemento, lo aggiungi a newList. Quindi, si segnala allo waitEvent che "qualcosa" è successo a newList.

Nella thread principale, è sufficiente attendere finché non si dispone di elementi sufficienti in newList e si attende questo attendendo le modifiche a newList, che informa waitEvent.

+0

Grazie! Adoro questo sito. –

+0

Prego. –

0

In base al protocollo HTTP, un client può solo aprire 2 connessioni a un servizio.

+0

http://blogs.msdn.com/b/wenlong/archive/2009/02/08/why-only-two-concurrent-requests-for-load-testing.aspx è d'accordo con te, ma indica un modo per risolvere quella; Ho intenzione di utilizzare la soluzione suggerita se ho raggiunto questa limitazione. –

+0

Il protocollo HTTP non ha limiti generali sulle connessioni, ma ha 2 connessioni (o 2 volte il numero di client per il codice proxy o gateway) come DOVREBBE per una buona ragione; in molti casi, 2 per server è il numero più efficiente da aprire alla volta. .NET applica questo, ma è configurabile. –