Tengo 5 URL y quiero hacer una solicitud Http para cada uno, y esperando la primera respuesta que tenga las condiciones.

List<string> urls; // url1, url2, ......

ParallelLoopResult result = Parallel.ForEach(urls, url=> GetTimeSlot(url));

private string GetTimeSlot(string url)
{
    HttpWebRequest wr = (HttpWebRequest)WebRequest.Create(url);

    HttpWebResponse response = (HttpWebResponse)wr.GetResponse();
        string responseString = new StreamReader(response.GetResponseStream(), Encoding.GetEncoding(response.CharacterSet)).ReadToEnd();
        if (responseString.Length < 6)
            return "";   //PARALEL RESUME
        else
            return responseString;   //PARALEL ENDS
}

Solo necesito la primera respuesta . ¿Es posible con Parallel o hay alguna forma mejor? Gracias.

0
Farzin Kanzi 4 mar. 2017 a las 20:44

2 respuestas

La mejor respuesta

Paralelo.ForEach estará bien para usar especialmente para su caso de uso. Solo use un token de cancelación para detener todas las demás tareas en ejecución.

 static void Main(string[] args)
    {
        var cts = new CancellationTokenSource();
        var _lock = new Object();
        var po = new ParallelOptions();
        po.CancellationToken = cts.Token;
        po.MaxDegreeOfParallelism = System.Environment.ProcessorCount;
        var listOfUrls = new List<string>() { "url1", "url2" };
        var responsResult = "";
        try
        {
            Parallel.ForEach(listOfUrls, po, (url) =>
            {
                po.CancellationToken.ThrowIfCancellationRequested();

                HttpWebRequest wr = (HttpWebRequest)WebRequest.Create(url);

                HttpWebResponse response = (HttpWebResponse)wr.GetResponse();
                string responseString = new StreamReader(response.GetResponseStream(), Encoding.GetEncoding(response.CharacterSet)).ReadToEnd();

                lock (_lock)
                {
                    if (responseString.Length > 6)
                    {
                       responsResult = responseString;
                        cts.Cancel();
                    }                        
                }           

            });
        }
        catch (OperationCanceledException e)
        {
            //cancellation was requested
        }
        finally
        {
            cts.Dispose();
        }
    }
2
Dynamikus 6 mar. 2017 a las 15:32

Puedes usar PLinq:

string firstResponse = urls
    .AsParallel()
    .Select(url => GetTimeSlot(url))
    .FirstOrDefault(r => ! string.IsNullOrEmpty(r))                
    ;
1
Henk Holterman 4 mar. 2017 a las 18:50