Od jakiegoś czasu używam HttpClient w środowisku wielowątkowym. Dla każdego wątku, kiedy inicjuje połączenie, utworzy zupełnie nowe wystąpienie HttpClient.
Niedawno odkryłem, że stosując to podejście, może to spowodować, że użytkownik otworzy zbyt wiele portów, a większość połączeń jest w stanie TIME_WAIT.
http://www.opensubscriber.com/message/[email protected]/86045.html
Dlatego zamiast robić każdy wątek:
HttpClient c = new HttpClient();
try {
c.executeMethod(method);
}
catch(...) {
}
finally {
method.releaseConnection();
}
Planujemy mieć:
[METODA A]
// global_c is initialized once through
// HttpClient global_c = new HttpClient(new MultiThreadedHttpConnectionManager());
try {
global_c.executeMethod(method);
}
catch(...) {
}
finally {
method.releaseConnection();
}
W normalnej sytuacji do global_c będzie miało dostęp 50 ++ wątków jednocześnie. Zastanawiałem się, czy spowoduje to jakiekolwiek problemy z wydajnością? Czy MultiThreadedHttpConnectionManager używa mechanizmu bez blokady do implementacji zasad bezpieczeństwa wątków?
Jeśli 10 wątków używa global_c, czy pozostałe 40 wątków zostanie zablokowanych?
A może byłoby lepiej, jeśli w każdym wątku utworzę wystąpienie HttpClient, ale jawnie zwolnię menedżera połączeń?
[METODA B]
MultiThreadedHttpConnectionManager connman = new MultiThreadedHttpConnectionManager();
HttpClient c = new HttpClient(connman);
try {
c.executeMethod(method);
}
catch(...) {
}
finally {
method.releaseConnection();
connman.shutdown();
}
Czy w przypadku connman.shutdown () występują problemy z wydajnością?
Czy mogę wiedzieć, która metoda (A lub B) jest lepsza dla aplikacji korzystającej z wątków 50 ++?
źródło
Metoda A jest zalecana przez społeczność programistów httpclient.
Więcej informacji można znaleźć pod adresem http://www.mail-archive.com/[email protected]/msg02455.html .
źródło
netstat
wykonuje przy tym naprawdę dobrą robotę. technet.microsoft.com/en-us/sysinternals/bb897437.aspx teżCzytam dokumentację, że sam HttpConnection nie jest traktowany jako bezpieczny wątkowo, a zatem MultiThreadedHttpConnectionManager zapewnia pulę HttpConnections wielokrotnego użytku, masz pojedynczy MultiThreadedHttpConnectionManager współużytkowany przez wszystkie wątki i zainicjowany dokładnie raz. Potrzebujesz więc kilku drobnych ulepszeń opcji A.
MultiThreadedHttpConnectionManager connman = new MultiThreadedHttpConnectionManag
Następnie każdy wątek powinien używać sekwencji dla każdego żądania, uzyskując połączenie z puli i umieszczając je z powrotem po zakończeniu pracy - użycie bloku last może być dobre. Należy również zakodować możliwość, że pula nie ma dostępnych połączeń i przetworzyć wyjątek limitu czasu.
HttpConnection connection = null try { connection = connman.getConnectionWithTimeout( HostConfiguration hostConfiguration, long timeout) // work } catch (/*etc*/) {/*etc*/} finally{ if ( connection != null ) connman.releaseConnection(connection); }
Ponieważ używasz puli połączeń, w rzeczywistości nie będziesz zamykać połączeń, więc nie powinno to mieć problemu z TIME_WAIT. To podejście zakłada, że każdy wątek nie zatrzymuje się długo na połączeniu. Zauważ, że sam conman pozostaje otwarty.
źródło
Myślę, że będziesz chciał użyć ThreadSafeClientConnManager.
Możesz zobaczyć, jak to działa, tutaj: http://foo.jasonhudgins.com/2009/08/http-connection-reuse-in-android.html
Lub w
AndroidHttpClient
którym używa go wewnętrznie.źródło
Za pomocą HttpClient 4.5 możesz to zrobić:
CloseableHttpClient httpClient = HttpClients.custom().setConnectionManager(new PoolingHttpClientConnectionManager()).build();
Zauważ, że ten implementuje Closeable (do zamykania menedżera połączeń).
źródło