Лучшая практика использования HttpClient в многопоточной среде

StackOverflow https://stackoverflow.com/questions/1281219

  •  16-09-2019
  •  | 
  •  

Вопрос

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

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

http://www.opensubscriber.com/message/commons-httpclient-dev@jakarta.apache.org/86045.html

Следовательно, вместо того, чтобы каждый поток выполнял:

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

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

[МЕТОД А]

// 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, но явно освобождал диспетчер соединений?

[МЕТОД Б]

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

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

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

Это было полезно?

Решение 2

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

Пожалуйста, обратитесь http://www.mail-archive.com/httpclient-users@hc.apache.org/msg02455.html Больше подробностей.

Другие советы

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

Если вы используете httpclient 4.x, диспетчер соединений вызывается ThreadSafeClientConnManager.Видеть это связь для получения более подробной информации (прокрутите вниз до «Диспетчер соединений пула»).Например:

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

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

MultiThreadedHttpConnectionManager connman = new MultiThreadedHttpConnectionManag

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

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 остается открытым.

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

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

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

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

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top