代码之家  ›  专栏  ›  技术社区  ›  Marcus Leon

为什么将输入读取为流而不是字符串更有效?

  •  7
  • Marcus Leon  · 技术社区  · 15 年前

    我们正在使用httpclient实现RESTAPI。

    我们正在读取服务器响应,使用:

    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.
    

    这个 docs 继续说:

    httpclient能够 请求/响应正文流。大的 可提交或接收实体 在内存中没有缓冲。这个 如果是多个 可以执行HTTP方法 同时地。虽然有 方便的处理方法 字符串或字节等实体 数组,不鼓励使用它们。 除非小心使用,否则很容易 导致内存不足, 因为它们意味着缓冲 内存中的完整实体。

    所以我的问题是,如果您确实需要字符串形式的完整响应(例如:存储在数据库中,或者使用DOM进行解析),那么为什么使用流更节省内存呢?

    4 回复  |  直到 15 年前
        1
  •  13
  •   matt b    15 年前

    使用流而不是将整个实体作为字符串更有效,因为后者意味着

    1. 在将响应的全部内容返回到代码之前,需要先读取它们,并且
    2. 在服务器发送整个响应之前,无法将控件返回到代码。

    如果您以流的形式处理响应,那么实际上您要做的是一次处理N个字节。这意味着您可以在远程服务器仍在发送下一段数据时开始处理第一个响应段。因此,作为一种访问方法,这更有意义 如果 您的用例允许您在收到数据时对其进行处理。

    但是,如果您出于任何原因需要将整个响应作为字符串,那么流方法的所有效率与您没有任何关系——因为即使您以片段形式读取响应,您仍然需要等待整个响应——并将其全部包含在单个字符串中——然后才能处理它。

    只有当您有一个用例,在这个用例中您可以在拥有整个响应主体之前开始处理响应时,流的使用效率才对您可用。

        2
  •  4
  •   Guffa    15 年前

    整个过程的内存效率并不高。如果从流中读取数据并将其放入字符串中,则只需将进程分成两部分,这样httpclient类就不会注意到它。

    如果您确实需要整个字符串,那么可以忽略该警告。然后由您来确定每个请求不会占用太多内存,这样服务器就不容易被DoS攻击击倒。

        3
  •  1
  •   pstanton    15 年前

    你的问题混淆了这一点。

    如果您绝对需要整个响应作为一个字符串,那么就这样做,

    但如果你能摆脱它,就用溪流吧。

    当您将整个响应加载到一个字符串中时,整个响应主体会同时出现在内存中。

    使用流,一次只有一小部分响应保存在内存中。

    文档说明,尤其是在同时处理多个大型请求时,将整个请求体加载到字符串中需要大量的内存。

        4
  •  0
  •   Suppressingfire    15 年前

    如果你分析成 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());