2010-11-12 21 views
6

Necesito realizar varias llamadas asíncronas desde un servicio wcf alojado en IIS (podría ser relevante, no sé). Las llamadas son a otros servicios, pero las realizo enviando una cadena a la URL del servicio. Llamarlos sincrónicamente funciona, pero tengo más de una docena de llamadas, y son completamente independientes, por lo que me gustaría acelerarlas llamándolos de forma asíncrona.Esperando múltiples solicitudes POST asíncronas

Ahora, me doy cuenta de que simplemente podría usar varios hilos para esto, y podría ser la solución más fácil, pero pensé que podría intentarlo de forma asíncrona.

Mi código es similar a esto:

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

lo anterior debe funcionar, creo; sin embargo, mi problema es que no tengo idea de cómo esperar hasta que todas las respuestas estén de vuelta. Si uso un contador y espero en un bucle hasta que llegue a cero, no quedará ninguna CPU para manejar las devoluciones de llamada. Lo mismo con usar alguna forma de semáforo, creo. ¿Hay una forma no bloqueante de esperar hasta que haya recuperado todas las respuestas? (Cambio de la firma del método tomar también una devolución de llamada sólo se moverá el problema a un nivel superior, me temo.)

[Editar] Aquí hay una muy cerca de pregunta - How to invoke async operation as sync? - pero tengo que esperar en múltiples asíncrono operaciones.

Respuesta

3

Para esto utiliza AutoResetEvent.

Pruebe lo siguiente por sus dos últimas líneas:

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(); 

Todos los artículos deben ser completado cuando newList contiene tantos elementos como list. Cuando entra un nuevo artículo, lo agrega al newList. Luego, indica al waitEvent que "algo" le pasó al newList.

En el hilo principal, sólo tiene que esperar hasta que haya suficientes elementos de newList y esperar a que este esperando por cambios a newList, que le informa de waitEvent.

+0

¡Gracias! Amo este sitio –

+0

De nada. –

0

De acuerdo con el protocolo HTTP, un cliente solo puede abrir 2 conexiones a un servicio.

+0

http://blogs.msdn.com/b/wenlong/archive/2009/02/08/why-only-two-concurrent-requests-for-load-testing.aspx está de acuerdo con usted, pero indica una forma de corregir ese; Planeo usar la solución sugerida si alcanzo esa limitación. –

+0

El protocolo HTTP no tiene un límite general en las conexiones, pero tiene 2 conexiones (o 2 veces el número de clientes para el proxy o el código de puerta de enlace) como DEBERÍA por una buena razón; sí tiende a que, en muchos casos, 2 por servidor es el número más eficiente para tener abierto a la vez. .NET lo hace cumplir, pero es configurable. –

Cuestiones relacionadas