6

Pracuję nad aplikacją, która wymaga jednego typu wiadomości, aby trafić w bazę danych, i innego typu wiadomości, aby przejść do zewnętrznego api XML.HttpWebRequest i porty do zakończenia operacji wejścia/wyjścia

Muszę przetworzyć DUŻO ... jednym z największych wyzwań jest uzyskanie dobrej wydajności klasy HttpWebRequest. Początkowo zacząłem od używania standardowych metod synchronicznych i łączenia wątków. To nie było dobre.

Po pewnym lekturze przekonałem się, że zalecanym sposobem jest użycie metod Begin/End, aby przekazać pracę do portów zakończenia IO, co zwalnia pulę wątków i zapewnia lepszą wydajność. Wydaje się, że tak nie jest ... wydajność jest nieznacznie lepsza, ale z pewnością nie widzę zbyt dużych portów zakończenia operacji wejścia w porównaniu do wątków.

Mam wątek, który obraca się wokół i wysyła mi dostępne wątki robocze + porty zakończenia w wątku. Porty zakończeń są zawsze bardzo niskie (maks. Widziałem 9) i zawsze używam około 120 wątków roboczych (czasami więcej). Używam rozpoczęcia/zakończenia wzór dla wszystkich metod w httpwebrequest:

Begin/EndGetRequestStream 
Begin/EndWrite (Stream) 
Begin/EndGetResponse 
Begin/EndRead (Stream) 

robię to dobrze? Czy czegoś brakuje? Mogę używać (czasami) do 2048 połączeń http jednocześnie (z wyjścia netstat) - dlaczego numery portów zakończenia byłyby tak niskie?

Jeśli ktoś mógłby udzielić poważnej porady na temat tego, jak dobrze radzić sobie z tymi wątkami zarządzania, portami zakończenia i httpwebrequest, byłoby to niezwykle cenne!

EDIT: czy .NET jest rozsądnym narzędziem do tego? Czy mogę uzyskać dużą liczbę połączeń HTTP pracujących z .NET i stosem System.Net? Sugerowano użycie czegoś takiego jak WinHttp (lub jakiejś innej biblioteki C++) i wybranie go z .NET, ale nie jest to coś, co szczególnie chcę zrobić!

+0

Czy Twój zewnętrzny interfejs API odpowiednio obsługuje ładowanie? Mam usługę zewnętrzną, której używam, jeśli wysyłam zbyt wiele żądań, istnieje wymierna degeneracja wydajności na serwerze usług. – btlog

+0

@btlog -> tak, tak jakbym wyłączał niektórych zewnętrznych dostawców, inni dostawcy wydajniej spędzają czas (ale otrzymują taką samą liczbę połączeń). jeśli problem dotyczył woluminu po ich stronie, to bez względu na to, co zrobiłem innym usługom xml, nie wpłynęłoby to na pozostałe. – peteisace

Odpowiedz

6

Sposób, w jaki to rozumiem, nie wiąże portu wszystkie czas, w którym żądanie asynchroniczne jest zaległe - jest tylko "zajęty", gdy dane zostały zwrócone i są przetwarzane w odpowiedni wątek. Mam nadzieję, że nie masz zbyt wiele pracy do wykonania w oddzwanianiu, dlatego nie masz wielu działających portów w tym samym czasie.

Czy jesteś teraz rzeczywiście jednak słaba wydajność? Czy powodem do niepokoju są tylko niskie liczby? Czy uzyskujesz przepustowość, jakiej oczekujesz?

Jednym z problemów, które możesz może mieć to, że pula połączeń HTTP dla jednego hosta jest stosunkowo niewielka. Jeśli masz setki próśb na tę samą maszynę, domyślnie tylko 2 żądania będą w danym momencie wykonywane na , aby uniknąć ataku DoS-a na hosta, o którym mowa (i uzyskać korzyści z utrzymywania przy życiu). Możesz zwiększyć to programowo lub używając app.config. Oczywiście może to nie być problemem w Twojej sprawie, ponieważ problem został już naprawiony lub wszystkie żądania dotyczą różnych hostów. (Jeśli netstat pokazuje 2048 połączeń, to nie brzmi to źle.)

+0

Callback prawie nic nie robi - nawet odczyt strumienia + zapis jest wykonywany asynchronicznie (chociaż może to być częścią mojego problemu? Wszystkie przykłady widzę używanie odczytu synchronicznego, pisania i operacji strumienia żądania, Słaba wydajność: tak - i użyj stopera i wyślij wiadomość po zakończeniu, stoper będzie wynosił od <1 sekundy do ponad 60 sekund Podniosłem już ServicePointManager.DefaultConnecvtionLimit do 2048, używam KeepAlive, a netstat DID pokazuje 2048 połączeń as ESTABLISHED: – peteisace

+0

@peteisace: Wygląda na to, że robisz wszystkie właściwe rzeczy. Jak pewnie serwer faktycznie reaguje * szybko? Czy próbowałeś złapać zrzut Wireshark? –

+0

jeśli usunę jedno z zewnętrznych api z którym się komunikuję, mam lepsze czasy na t on inni, więc to zdecydowanie mój klient dzwoni. moja teoria mówi, że używam zbyt wielu wątków ThreadPoin i że prowadzi to do zbyt wielu wątków, które się odbijają, co oznacza, że ​​rzeczy nie mogą zostać przetworzone wystarczająco szybko, dlatego naprawdę chciałem zmusić porty do ukończenia, aby były dużo bardziej zajęci niż oni. PS nie używa całej dostępnej przepustowości! plus rzeczy http mają negatywny wpływ na moje wątki db, dlatego myślę, że to zbyt wiele wątków w puli. – peteisace

0

Być może metody EndRead powinny zapisywać wyniki tylko w kolejce wątków bezpiecznych, które następnie odczytujesz z niewielkiej liczby wątków roboczych, które są pod Twoją kontrolą . I/lub wykorzystaj fakt, że HttpWebRequest zasygnalizuje obiekt, który można oczekiwać, po zakończeniu i zapisze własną logikę, aby czekać na wszystkie zaległe żądania z pojedynczej (lub małej liczby) wątków.

0

Posiadanie tylko 9 wątków portu zakończenia faktycznie oznacza, że ​​prawdopodobnie używasz ich poprawnie i sprawnie. Zakładam, że maszyna, na której pracujesz, ma 8 rdzeni lub 4 rdzenie hiperwątkowe, co oznacza, że ​​system operacyjny będzie próbował w dowolnym momencie do 8 aktywnych (nie śpiących/blokujących/oczekujących) wątków portów zakończenia.

Jeśli jeden z uruchomionych wątków staje się nieaktywny (sleep/block/wait) i istnieją dodatkowe elementy do przetworzenia, zostanie utworzony dodatkowy wątek, aby utrzymać aktywny licznik na pozycji 8. Jeśli widzisz 9 wątków, to oznacza, że ​​nie wprowadzasz praktycznie żadnych blokad w metodach na twoich wątkach portowania i faktycznie pracujesz z CPU.

Jeśli masz 8 wątków aktywnie wykonujących pracę związaną z CPU na 8 rdzeniach, dodanie kolejnych wątków spowolni działanie (przełączanie kontekstów między wątkami będzie zmarnowanym czasem).

Na co powinieneś zwrócić uwagę, to dlaczego masz 120 innych wątków i co one robią.