Pregunta

Tengo una página que necesita combinar datos de cuatro webrequests diferentes en una sola lista de elementos. Actualmente, los estoy ejecutando secuencialmente, agregándolos a una sola lista y luego enlazándolos a mi repetidor.

Sin embargo, me gustaría poder llamar a estas cuatro solicitudes web de forma asíncrona para que puedan ejecutarse simultáneamente y ahorrar tiempo de carga. Desafortunadamente, todos los tutoriales y artículos asíncronos que he visto tratan con una sola solicitud, utilizando el controlador finalizado para continuar con el procesamiento.

¿Cómo puedo realizar los cuatro (¡esto podría incluso aumentar!) simultáneamente, teniendo en cuenta que cada resultado debe incluirse en una sola lista?

muchas gracias!

EDITAR: ejemplo simplificado de lo que estoy haciendo:

var itm1 = Serialize(GetItems(url1));
list.AddRange(itm1);
var itm2 = Serialize(GetItems(url2));
list.AddRange(itm2); 

string GetItems(string url)
{
     var webRequest = WebRequest.Create(url) as HttpWebRequest;
     var response = webRequest.GetResponse() as HttpWebResponse;

     string retval;
     using (var sr = new StreamReader(response.GetResponseStream()))
     { retval = sr.ReadToEnd(); }
     return retval;
} 
¿Fue útil?

Solución

Esto debería ser realmente simple ya que sus datos finales dependen del resultado de las cuatro solicitudes.

Lo que puede hacer es crear 4 delegados asíncronos, cada uno de los cuales apunta al método web apropiado. Haz un BeginInvoke en todos ellos. Y luego use WaitHandle para esperar a todos. No es necesario utilizar devoluciones de llamada, en su caso, ya que no desea continuar mientras se procesan los métodos web, sino que debe esperar hasta que todos los métodos web terminen de ejecutarse.

Solo después de que se ejecuten todos los métodos web, se ejecutará el código después de la instrucción de espera. Aquí puedes combinar los 4 resultados.

Aquí hay un código de ejemplo que desarrollé para ti:

class Program
    {
        delegate string DelegateCallWebMethod(string arg1, string arg2);

        static void Main(string[] args)
        {
            // Create a delegate list to point to the 4 web methods
            // If the web methods have different signatures you can put them in a common method and call web methods from within
            // If that is not possible you can have an List of DelegateCallWebMethod
            DelegateCallWebMethod del = new DelegateCallWebMethod(CallWebMethod);

            // Create list of IAsyncResults and WaitHandles
            List<IAsyncResult> results = new List<IAsyncResult>();
            List<WaitHandle> waitHandles = new List<WaitHandle>();

            // Call the web methods asynchronously and store the results and waithandles for future use
            for (int counter = 0; counter < 4; )
            {
                IAsyncResult result = del.BeginInvoke("Method ", (++counter).ToString(), null, null);
                results.Add(result);
                waitHandles.Add(result.AsyncWaitHandle);
            }

            // Make sure that further processing is halted until all the web methods are executed
            WaitHandle.WaitAll(waitHandles.ToArray());

            // Get the web response
            string webResponse = String.Empty;
            foreach (IAsyncResult result in results)
            {
                DelegateCallWebMethod invokedDel = (result as AsyncResult).AsyncDelegate as DelegateCallWebMethod;
                webResponse += invokedDel.EndInvoke(result);
            }
        }


        // Web method or a class method that sends web requests
        public static string CallWebMethod(string arg1, string arg2)
        {
            // Code that calls the web method and returns the result

            return arg1 + " " + arg2 + " called\n";
        }

    }

Otros consejos

¿Qué hay de lanzar cada solicitud en su propio hilo y luego agregar los resultados a la lista?

puedes probar el siguiente código:

Paralelo.Invocar (() = >                         {
                            // TODO ejecuta tus solicitudes ...                         });

Necesita referencias de extensiones paralelas: http://msdn.microsoft.com/en-us/concurrency/bb896007. aspx

@Josh: con respecto a su pregunta sobre el envío de 4 (potencialmente más) solicitudes asincrónicas y el seguimiento de las respuestas (por ejemplo, para alimentar en una lista). Puede escribir 4 solicitudes y 4 manejadores de respuestas, pero dado que potencialmente tendrá más solicitudes, puede escribir un bucle asíncrono. Un clásico para el bucle está hecho de un init, una condición y un incremento. Puede desglosar un clásico for en un ciclo while y seguir siendo equivalente. Luego haces el bucle while en una función recursiva. Ahora puedes hacerlo asíncrono. Puse algunos scripts de muestra aquí en http://asynchronous.me/ . En su caso, seleccione el bucle for en las opciones. Si desea que las solicitudes se envíen en secuencia, es decir, una solicitud después de la respuesta anterior (solicitud1, respuesta1, solicitud2, respuesta2, solicitud3, respuesta3, etc.), seleccione Comunicación en serie (es decir, secuencial), pero el código es un poco más intrincado. Por otro lado, si no le importa el orden en que se reciben las respuestas (orden aleatorio), elija Comunicación paralela (es decir, concurrente), el código es más intuitivo. En cualquier caso, cada respuesta se asociará con su solicitud correspondiente mediante un identificador (un entero simple) para que pueda realizar un seguimiento de todas ellas. El sitio le dará un script de muestra. Las muestras están escritas en JavaScript pero es aplicable a cualquier idioma. Adapte el script a su idioma y preferencias de codificación. Con esa secuencia de comandos, su navegador enviará 4 solicitudes de forma asincrónica, y mediante el identificador podrá realizar un seguimiento de a qué solicitud corresponde la respuesta. Espero que esto ayude. / Thibaud Lopez Schneider

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top