Почему эффективнее использовать память для чтения ввода в виде потока, а не строки?

Мы используем HTTPClient для реализации REST API.

Мы читаем ответ сервера, используя:

method = new PostMethod(url);
HttpClient client = new HttpClient();
int statusCode = client.executeMethod(method);
String responseBody = method.getResponseBodyAsString();

Когда мы делаем это, мы получаем это предупреждение:

Dec 9, 2009 7:41:11 PM org.apache.commons.httpclient.HttpMethodBase getResponseBody
WARNING: Going to buffer response body of large or unknown size. Using getResponseBodyAsStream instead is recommended.

Далее в документах говорится:

HttpClient поддерживает эффективную потоковую передачу тела запроса/ответа. Большие объекты могут быть отправлены или получены без буферизации в памяти. Это особенно важно, если несколько HTTP-методов могут выполняться одновременно. Хотя существуют удобные методы для работы с сущностями, такими как строки или массивы байтов, их использование не рекомендуется. Если их не использовать осторожно, они могут легко привести к нехватке памяти, поскольку они предполагают буферизацию всего объекта в памяти.

Итак, мой вопрос: если вам нужен полный ответ в виде строки (т. Е. Для хранения в БД или для анализа с использованием DOM), почему использование потока более эффективно для памяти?


person Marcus Leon    schedule 10.12.2009    source источник


Ответы (4)


Более эффективно использовать поток, а не получать весь объект в виде строки, потому что последнее означает, что

  1. все содержимое ответа необходимо прочитать, прежде чем его можно будет вернуть в ваш код, и
  2. управление не может быть возвращено вашему коду, пока весь ответ не будет отправлен сервером.

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

Однако, если вам по какой-либо причине нужен весь ответ в виде строки, тогда все эффективности метода потока не имеют к вам никакого отношения, потому что даже если вы читаете ответ по частям, вам все равно нужно дождаться всего ответа - и все это содержится в одной строке, прежде чем вы сможете ее обработать.

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

person matt b    schedule 10.12.2009

Весь процесс не более эффективен в использовании памяти. Если вы читаете из потока и помещаете его в строку, вы просто разделяете процесс на две части, чтобы класс HttpClient этого не заметил.

Если вам действительно нужна вся строка, вы можете игнорировать предупреждение. Затем вам нужно убедиться, что он не использует слишком много памяти на запрос, чтобы сервер не мог быть легко отключен DoS-атакой.

person Guffa    schedule 10.12.2009

ваш вопрос сбивает с толку.

если вам АБСОЛЮТНО нужен весь ответ в виде строки, сделайте это,

но если вам это вообще сойдет с рук, используйте потоки.

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

при использовании потоков в памяти одновременно хранится только небольшая часть ответа.

в документации говорится, что, особенно с несколькими большими запросами одновременно, загрузка всего тела запроса в строку потребует много памяти.

person pstanton    schedule 10.12.2009

Если вы выполняете синтаксический анализ в org.w3c.Document (или, что еще лучше, в org.jdom.Document), очень легко напрямую использовать поток. Бывший:

org.apache.http.HttpResponse hr = httpClient.execute(httpRequest);
org.apache.http.HttpEntity he = hr.getEntity();
org.jdom.input.SAXBuilder builder = new SAXBuilder();
org.jdom.Document document = builder.build(he.getContent());
person Suppressingfire    schedule 10.12.2009