2009-08-15 5 views
78

Некоторое время я использовал HttpClient в многопоточной среде. Для каждого потока, когда он инициирует соединение, он создаст совершенно новый экземпляр HttpClient.Лучшая практика использования HttpClient в многопоточной среде

Недавно я обнаружил, что с помощью этого подхода пользователь может открыть слишком много портов, и большинство соединений находятся в состоянии TIME_WAIT.

http://www.opensubscriber.com/message/[email protected]/86045.html

Таким образом, вместо того, чтобы каждый поток делает:

HttpClient c = new HttpClient(); 
try { 
    c.executeMethod(method); 
} 
catch(...) { 
} 
finally { 
    method.releaseConnection(); 
} 

Мы планируем:

[Способ A]

// global_c is initialized once through 
// HttpClient global_c = new HttpClient(new MultiThreadedHttpConnectionManager()); 

try { 
    global_c.executeMethod(method); 
} 
catch(...) { 
} 
finally { 
    method.releaseConnection(); 
} 

В нормальной ситуации, global_c одновременно будут доступны потоки 50 ++. Мне было интересно, это создаст какие-либо проблемы с производительностью? Является ли MultiThreadedHttpConnectionManager использующим механизм блокировки для реализации политики безопасности потоков?

Если 10 потоков используют global_c, будут ли заблокированы остальные 40 потоков?

Или было бы лучше, если бы в каждом потоке я создавал экземпляр HttpClient, но явным образом освобождаю диспетчер соединений?

[МЕТОД B]

MultiThreadedHttpConnectionManager connman = new MultiThreadedHttpConnectionManager(); 
HttpClient c = new HttpClient(connman); 
try { 
     c.executeMethod(method); 
} 
catch(...) { 
} 
finally { 
    method.releaseConnection(); 
    connman.shutdown(); 
} 

Будет connman.shutdown() страдают проблемы с производительностью?

Могу ли я узнать, какой метод (A или B) лучше для приложения, использующего потоки 50 ++?

ответ

16

Метод A рекомендуется сообществом разработчиков httpclient.

Для получения более подробной информации, пожалуйста, обратитесь к http://www.mail-archive.com/[email protected]/msg02455.html.

+1

Когда вы вызовете «shutdown» в диспетчере соединений, если клиент сделан глобальным. –

+1

Какие инструменты/команды linux полезны для отладки или «визуализации» поведения ConnectionManager под капотом? Я спрашиваю, потому что у нас в настоящее время возникают проблемы с подключениями в CLOSE_WAIT и другими эффектами, и мы изо всех сил пытаемся найти хороший способ увидеть, что именно происходит. – Christoph

+0

@WandMaker. Я уверен, что вы просто вызовете выключение, когда либо программа выйдет, либо когда вы закончите с некоторой периодичностью работы, где вам не понадобятся какие-либо соединения в течение некоторого времени. –

12

Мое чтение документов заключается в том, что сам HttpConnection не рассматривается как потокобезопасный, и, следовательно, MultiThreadedHttpConnectionManager предоставляет многоразовый пул HttpConnections, у вас есть один MultiThreadedHttpConnectionManager, общий для всех потоков и инициализируемый ровно один раз. Так что вам нужно несколько небольших уточнений к варианту А.

MultiThreadedHttpConnectionManager connman = new MultiThreadedHttpConnectionManag 

Затем каждый поток должен использовать последовательность для каждого запроса, получение от СВЯЗИ бассейна и положить его обратно по завершению своей работы - с использованием наконец блок может быть хорошим. Вы также должны указать, что пул не имеет доступных подключений и обрабатывает исключение таймаута.

HttpConnection connection = null 
try { 
    connection = connman.getConnectionWithTimeout(
         HostConfiguration hostConfiguration, long timeout) 
    // work 
} catch (/*etc*/) {/*etc*/} finally{ 
    if (connection != null) 
     connman.releaseConnection(connection); 
} 

Как вы используете пул соединений, вы на самом деле не закрывать соединения и поэтому это не должно ударить проблему TIME_WAIT. Этот подход позволяет предположить, что каждый поток не поддерживает связь в течение долгого времени. Обратите внимание, что сам conman остается открытым.

+0

Не было фактического ответа на мой вопрос, по какому методу (A или B) лучше. –

+4

Ответ был тот, что ни один из них не является правильным. Я объясню это. – djna

5

Я думаю, вы захотите использовать ThreadSafeClientConnManager.

Вы можете увидеть, как это работает здесь: http://foo.jasonhudgins.com/2009/08/http-connection-reuse-in-android.html

Или в AndroidHttpClient, который использует его внутренне.

+1

Opps. Не планируете мигрировать с HttpClient 3.x на 4.x, так как 3.x работает безупречно в моем приложении почти на 2 года :) –

+9

Конечно, если кто-то еще сюда пришел Googling для ответа :) –

41

Определенно метод А, потому что его объединенный и потокобезопасный.

Если вы используете httpclient 4.x, диспетчер соединений называется ThreadSafeClientConnManager. См. Это link для получения дополнительной информации (прокрутите вниз до «Менеджер подключения пулов»). Например:

HttpParams params = new BasicHttpParams(); 
    SchemeRegistry registry = new SchemeRegistry(); 
    registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80)); 
    ClientConnectionManager cm = new ThreadSafeClientConnManager(params, registry); 
    HttpClient client = new DefaultHttpClient(cm, params); 
+44

[ThreadSafeClientConnManager ] (http://hc.apache.org/httpcomponents-client-ga/httpclient/apidocs/org/apache/http/impl/conn/tsccm/ThreadSafeClientConnManager.html) устарел в пользу [PoolingClientConnManager] (http: //hc.apache.org/httpcomponents-client-ga/httpclient/apidocs/org/apache/http/impl/conn/PoolingClientConnectionManager.html) в 4.2 –

+0

Привет, может ли httpclient, созданный этим методом, использоваться для поддержания сеанса как описанный здесь http://stackoverflow.com/questions/5960832/maintaining-session-in-android-application-stay-authenticated-on-the-server-si ...? Потому что, когда я пытался, я не смог поддерживать сеанс через разные запросы ... – sakthig

+11

4.3.1 здесь: PoolingClientConnManager устарел в пользу PoolingHttpClientConnectionManager. – Matthias

0

С HttpClient 4,5 вы можете сделать это:

CloseableHttpClient httpClient = HttpClients.custom().setConnectionManager(new PoolingHttpClientConnectionManager()).build(); 

Обратите внимание, что это один реализует закрывающиеся (для отключения диспетчера соединений).

Смежные вопросы