5

Próbuję zaimplementować klasę helper/utility środowiska .NET 4, która powinna pobrać źródła strony HTML na podstawie listy adresów URL narzędzia WebTest. Rozwiązanie powinno być skalowalne i mieć wysoką wydajność.Jak wykonywać wielowątkowość za pomocą asynchronicznych zapytań webowych

Badam i próbuję różnych rozwiązań już od wielu dni, ale nie mogę znaleźć odpowiedniego rozwiązania.

W oparciu o moje zrozumienie najlepszym sposobem osiągnięcia mojego celu byłoby wykorzystanie asynchronicznych wystąpień webowych działających równolegle przy użyciu licencji TPL.

Aby mieć pełną kontrolę nad nagłówkami itp. Używam HttpWebResponse zamiast WebClient, który owija HttpWebResponse. W niektórych przypadkach dane wyjściowe powinny być powiązane z innymi zadaniami, dlatego wykorzystanie zadań TPL może mieć sens.

Co udało mi się osiągnąć do tej pory po wielu różnych prób/podejść,

  1. Wdrożone podstawowe synchroniczny, asynchroniczny (APM) i równolegle (z wykorzystaniem zadań OC) rozwiązań, aby zobaczyć poziom skuteczności różnych rozwiązań.

  2. Aby zobaczyć wydajność asynchronicznego rozwiązania równoległego, zastosowałem podejście APM, BeginGetResponse i BeginRead i uruchomiłem je w Parallel.ForEach. Wszystko działa dobrze i jestem zadowolony z wydajności. Jakoś czuję, że za pomocą prostego Parallel.ForEach nie ma sposobu, aby przejść i na przykład nie wiem, w jaki sposób będę używać łańcuchów zadań.

  3. Potem próbowałem bardziej wyrafinowanego systemu, używając zadań do zawijania rozwiązania APM, używając TaskCompletionSource i iteratora do iteracji przez przepływ APM. Uważam, że to rozwiązanie może być tym, czego szukam, ale jest dziwne opóźnienie, coś pomiędzy 6-10, co dzieje się 2-3 razy przy uruchomieniu listy 500 adresów URL.

    Na podstawie dzienników wykonanie powróciło do wątku, który wywołuje asynchroniczne pobieranie w pętli w momencie wystąpienia opóźnienia. Opóźnienie nie występuje zawsze, gdy wykonanie powraca do pętli, tylko 2-3 razy, innym razem działa dobrze. Wygląda na to, że wątek z pętlą tworzy zestaw zadań, które będą przetwarzane przez inne wątki i podczas wykonywania większości/wszystkich zadań będzie opóźnienie (6-8s), zanim pętla będzie kontynuować tworzenie pozostałych zadań i inne wątki będą znowu aktywne .

Zasada iterator wewnątrz pętli:

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

mam rozwiązanie limit połączeń za pomocą System.Net.ServicePointManager.DefaultConnectionLimit i limit czasu korzystania ThreadPool.RegisterWaitForSingleObject

Moje pytanie po prostu, jakie byłoby najlepsze podejście do implementacji klasy helper/utility do pobierania stron html, która byłaby:

  • być skalowalne i mają wysoką wydajność
  • użytku webrequests
  • łatwo przykuty do innych zadań
  • być w stanie wykorzystać timeout
  • wykorzystanie.NET 4 ramy

Jeśli uważasz, że rozwiązanie z użyciem APM TaskCompletionSource i iterator, który przedstawiłem powyżej, jest w porządku Będę wdzięczny za każdą pomoc dla próby rozwiązania problemu opóźnienia.

Jestem całkowicie nowy w rozwoju C# i Windows, więc proszę nie zwracać uwagi, jeśli coś, co próbuję, nie ma zbytniego sensu.

Każda pomoc będzie bardzo cenna, ponieważ bez rozwiązania tego problemu muszę zrezygnować z rozwijania mojego narzędzia testowego.

Dzięki

+0

Czy możesz wyjaśnić bardziej szczegółowo, w jaki sposób korzystasz z iteratora i dlaczego twoim zdaniem warto go używać jako iteratora? – svick

+0

Po wypróbowaniu różnych rozwiązań skończyło się na używaniu iteratorów opartych na poradach ekspertów MS na blogu msdn. Moje rozwiązanie jest mniej więcej takie samo jak na blogu, po prostu dodano timeout i logowanie. Nie mam żadnego konkretnego powodu do korzystania z iteratorów i jestem otwarty na każde rozwiązanie, które działa. Link do fragmentu kodu: http://social.msdn.microsoft.com/Forums/en-US/parallelextensions/thread/95355648-1fa6-4b2d-a260-954c3421c453/ – Laowai

Odpowiedz

0

Korzystanie iteratory doskonałym rozwiązaniem w pre-OC .NET (np koordynacji i współbieżności Runtime (CCR) z MS Robotics popełnił ciężki korzystania z nich i pomógł zainspirować TPL). Jednym z problemów jest to, że same iteratory nie dadzą ci tego, czego potrzebujesz - potrzebujesz również harmonogramu, aby efektywnie dystrybuować obciążenie. To prawie zrobione przez urywek Stephena Toub, że jesteś związana - należy jednak pamiętać, że jedna linia:

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

myślę, że sporadyczne problemy jesteś widząc może być związana zmuszając „ExecuteSynchronously” - może to być przyczyną nierównomierny rozkład pracy w dostępnych rdzeniach/wątkach.

Zapoznaj się z innymi alternatywami, które Stephen proponuje in his blog article. W szczególności zobacz, co zrobi proste wywoływanie połączeń ContinueWith() (jeśli to konieczne, po którym następuje dopasowanie wywołań Unwrap()). Składnia nie będzie najładniejsza, ale jest najprostsza i w jak najmniejszym stopniu ingeruje w środowisko wykonawcze kradnące pracę, więc masz nadzieję, że uzyskasz lepsze wyniki.

+0

Dziękujemy za sugestie i uwagi. Będę bliżej przyjrzeć się blogowi Stephena. – Laowai

+0

Pewnie! Daj nam znać, co znajdziesz ... –

Powiązane problemy