5

Sto provando a implementare .NET 4 helper/utility class che dovrebbe recuperare sorgenti di pagine HTML basate sull'elenco url per lo strumento di webtesting. La soluzione dovrebbe essere scalabile e avere prestazioni elevate.Come fare multi-threading con richieste web asincrone

Ho cercato e provato diverse soluzioni già da molti giorni, ma non riesco a trovare una soluzione adeguata.

Sulla base della mia comprensione il modo migliore per raggiungere il mio obiettivo sarebbe quello di utilizzare le richieste web asincrone in parallelo utilizzando TPL.

Per avere il controllo completo delle intestazioni ecc. Uso HttpWebResponse invece di WebClient che include HttpWebResponse. In alcuni casi, l'output dovrebbe essere incatenato ad altre attività, quindi l'utilizzo delle attività TPL potrebbe avere senso.

Quello che ho realizzato finora dopo molti differenti prove/approcci,

  1. Implementato sincrono di base, asincrono (APM) e parallela (con compiti TPL) soluzioni per vedere il livello di prestazioni delle soluzioni diverse.

  2. Per visualizzare le prestazioni della soluzione parallela asincrona, ho utilizzato l'approccio APM, BeginGetResponse e BeginRead ed eseguito in Parallel.ForEach. Tutto funziona bene e sono contento della prestazione. In qualche modo sento che usare il semplice Parallel.ForEach non è la strada da percorrere e per esempio non so come utilizzerei il concatenamento delle attività.

  3. Quindi ho provato un sistema più sofisticato utilizzando le attività per il wrapping della soluzione APM utilizzando TaskCompletionSource e iterator per scorrere il flusso APM. Credo che questa soluzione potrebbe essere ciò che sto cercando, ma c'è uno strano ritardo, qualcosa tra 6-10 secondi, che accade 2-3 volte quando si esegue una lista di 500 url.

    In base ai registri, l'esecuzione è tornata alla thread che chiama async fetch in un ciclo quando si verifica il ritardo. Il ritardo non si verifica sempre quando l'esecuzione ritorna al ciclo, solo 2-3 volte, altre volte funziona bene. Sembra che il thread in loop creerebbe una serie di attività che sarebbero state elaborate da altri thread e mentre la maggior parte/tutte le attività sono state completate ci sarebbe un ritardo (6-8 secondi) prima che il ciclo continui a creare attività rimanenti e altri thread siano di nuovo attivi .

Il principio di iteratore looping è:

IEnumerable<Task> DoExample(string input) 
    { 
    var aResult = DoAAsync(input); 
    yield return aResult; 
    var bResult = DoBAsync(aResult.Result); 
    yield return bResult; 
    var cResult = DoCAsync(bResult.Result); 
    yield return cResult; 
    … 
    } 

Task t = Iterate(DoExample(“42”)); 

che sto risolvendo il limite di connessione utilizzando System.Net.ServicePointManager.DefaultConnectionLimit e timeout utilizzando ThreadPool.RegisterWaitForSingleObject

La mia domanda è semplicemente, quale sarebbe l'approccio migliore per implementare la classe helper/utility per il recupero di pagine html che:

  • essere scalabile e ad alte prestazioni hanno
  • uso webrequests
  • essere facilmente incatenato ad altri compiti
  • essere in grado di utilizzare timeout
  • uso.NET 4 framework
  • Se si pensa che la soluzione per l'utilizzo di APM, TaskCompletionSource e iterator, che ho presentato sopra, sia soddisfacente, gradirei qualsiasi aiuto nel tentativo di risolvere il problema del ritardo.

    Sono totalmente nuovo a C# e allo sviluppo di Windows, quindi per favore non importa se qualcosa che sto provando non ha molto senso.

    Qualsiasi aiuto sarebbe molto apprezzato poiché senza ottenere questo risultato, devo abbandonare lo sviluppo del mio strumento di test.

    Grazie

    +0

    Potresti spiegare più in dettaglio come stai usando l'iteratore e perché pensi che sia utile averlo effettivamente come iteratore? – svick

    +0

    Dopo aver provato varie soluzioni, ho finito per usare iteratori basati sui consigli degli esperti di MS sul blog di msdn. La mia soluzione è più o meno la stessa del blog, ho aggiunto solo il timeout e la registrazione. Non ho alcun motivo specifico per utilizzare gli iteratori e sono aperto a qualsiasi soluzione che funzioni. Link allo snippet di codice: http://social.msdn.microsoft.com/Forums/en-US/parallelextensions/thread/95355648-1fa6-4b2d-a260-954c3421c453/ – Laowai

    risposta

    0

    Uso iteratori era una grande soluzione nel pre-TPL .NET (ad esempio, il coordinamento e la concorrenza Runtime (CCR) di MS Robotics fatto uso pesante di loro e ha contribuito a ispirare TPL). Un problema è che gli iteratori da soli non ti daranno quello che ti serve - hai anche bisogno di un programmatore per distribuire efficacemente il carico di lavoro. Ecco quasi fatto da frammento di Stephen Toub che si è collegato al - ma si noti che una riga:

    enumerator.Current.ContinueWith(recursiveBody, TaskContinuationOptions.ExecuteSynchronously); 
    

    credo che i problemi intermittenti che stai vedendo potrebbe essere collegato a forzare "ExecuteSynchronously" - potrebbe essere la causa di un distribuzione non uniforme del lavoro tra i core/thread disponibili.

    Dai un'occhiata ad alcune delle alternative che Stephen propone in his blog article. In particolare, guarda cosa farebbe una semplice concatenazione delle chiamate ContinueWith() (se necessario, seguita da corrispondenti chiamate Unwrap()). La sintassi non sarà la più bella, ma è la più semplice e interferisce il meno possibile con il runtime di base per il furto del lavoro, quindi speriamo di ottenere risultati migliori.

    +0

    Grazie per i vostri suggerimenti e commenti. Darò più da vicino il blog di Stephen. – Laowai

    +0

    Sicuro! Facci sapere cosa trovi ... –

    Problemi correlati