Как использовать HttpAsyncClient с многопоточными операциями?

Тесно связан с этим вопросом: как использовать HttpClient с многопоточными операциями? Мне интересно, является ли Apache HttpAsyncClient потокобезопасным, или он также требует использования MultiThreadedHttpConnectionManager или ThreadSafeClientConnManager.

Если для этого требуется такой диспетчер соединений, существует ли он в асинхронных библиотеках?

Мне удалось найти PoolingClientAsyncConnectionManager в асинхронных библиотеках, но я не уверен, что это то, что мне нужно.

С другой стороны, я думал об использовании ThreadLocal для создания одного объекта HttpAsyncClient на поток.

Обратите внимание, что в отличие от вопроса, на который я ссылался ранее, мне нужно, чтобы состояние было независимым между сеансами, даже если несколько сеансов затрагивают один и тот же домен. Если в сеансе 1 установлен файл cookie, он не должен быть виден в сеансе 2. По этой причине я также рассмотрел возможность создания нового объекта HttpAsyncClient для каждого отдельного запроса, хотя у меня сложилось впечатление, что должен быть лучший способ,

Благодарю.

2 ответа

Решение

После нагрузочного тестирования как с PoolingClientAsyncConnectionManager, так и без него мы обнаружили, что мы получили противоречивые результаты, когда не использовали PoolingClientAsyncConnectionManager.

Среди прочего, мы отслеживали количество Http-вызовов, которые мы делали, и количество Http-вызовов, которые были завершены (с помощью отмененных (...), завершенных (...) или сбойных (...) функций связанного FutureCallback). Без PoolingClientAsyncConnectionManager и при большой нагрузке эти две цифры иногда не совпадали, что наводило нас на мысль, что где-то некоторые соединения растоптаны информацией о соединении из других потоков (только предположение).

В любом случае, с помощью PoolingClientAsyncConnectionManager показатели всегда совпадали, и нагрузочные тесты были успешными, поэтому мы определенно используем его.

Окончательный код, который мы использовали, выглядит так:

public class RequestProcessor {
  private RequestProcessor instance = new RequestProcessor();
  private PoolingClientAsyncConnectionManager pcm = null;
  private HttpAsyncClient httpAsyncClient = null;
  private RequestProcessor() {
    // Initialize the PoolingClientAsyncConnectionManager, and the HttpAsyncClient 
  }
  public void process(...) {
    this.httpAsyncClient.execute(httpMethod, 
         new BasicHttpContext(), // Use a separate HttpContext for each request so information is not shared between requests
         new FutureCallback<HttpResponse>() {
      @Override
      public void cancelled() {
        // Do stuff
      }
      @Override
      public void completed(HttpResponse httpResponse) {
        // Do stuff
      }
      @Override
      public void failed(Exception e) {
        // Do stuff
      }
    });
  }
}

Вы упоминаете "независимый через сессии". Если это просто означает, что куки, то я бы подумал создать свой собственный CookieStore который очищается, когда каждый из ваших потоков идет использовать HttpClient было бы достаточно.

я хотел бы использовать ThreadLocal чтобы создать клиент для каждого потока, не используйте диспетчер общих подключений, а затем агрессивно очищайте файлы cookie. Этот ответ был полезен при очистке файлов cookie:

Android HttpClient постоянные куки

Что-то вроде следующего кода будет работать. Я переопределил ThreadLocal.get() метод для вызова clear() в случае, если каждый запрос независим. Вы также можете позвонить ясно в execute(...) метод.

private static final ThreadLocal<ClientContext> localHttpContext = 
    new ThreadLocal<ClientContext> () {
        @Override
        protected ClientContext initialValue() {
           return new ClientContext();
        }
        @Override
        public ClientContext get() {
           ClientContext clientContext = super.get();
           // could do this to clear the context before usage by the thread
           clientContext.clear();
           return clientContext;
        }
    };
...

ClientContext clientContext = localHttpContext.get();
// if this wasn't in the get method above
// clientContext.clear();
HttpGet httpGet = new HttpGet("http://www.google.com/");
HttpResponse response = clientContext.execute(httpGet);
...

private static class ClientContext {
    final HttpClient httpClient = new DefaultHttpClient();
    final CookieStore cookieStore = new BasicCookieStore();
    final HttpContext localContext = new BasicHttpContext();
    public ClientContext() {
         // bind cookie store to the local context
         localContext.setAttribute(ClientContext.COOKIE_STORE, cookieStore);
    }
    public HttpResponse execute(HttpUriRequest request) {
         // in case you want each execute to be indepedent
         // clientContext.clear();
         return httpClient.execute(request, httpContext);
    }
    public void clear() {
         cookieStore.clear();
    }
}
Другие вопросы по тегам