【发布时间】:2014-03-14 21:35:48
【问题描述】:
我编写了一个 HTTP 服务器,它可以生成由 JSON 结构事件组成的无穷无尽的 HTTP 流。类似于 Twitter 的流媒体 API。这些事件由\n 分隔(根据Server-sent events with Content-Type:text/event-stream)并且长度可能不同。
回应是
- 由于无限流而分块(HTTP 1.1 Transfer-Encoding:chunked)
- 压缩(内容编码:gzip)以节省带宽。
我想在 Python 中尽快使用这些行,并尽可能节省资源,而无需重新发明轮子。
由于我目前正在使用 python-requests,你知道如何使它工作吗? 如果您认为 python-requests 在这里无济于事,我完全愿意接受替代框架/库。
我当前的实现基于requests 并使用iter_lines(...) 来接收行。但是chunk_size 参数很棘手。如果设置为1,它会占用大量 CPU,因为某些事件可能会达到几千字节。如果设置为大于 1 的任何值,则某些事件会卡住,直到下一次到达并且整个缓冲区“被填满”。事件之间的时间可以是几秒钟。
我预计chunk_size 是某种“要接收的最大字节数”,就像在 unix 的recv(...) 中一样。相应的手册页说:
接收调用通常会返回任何可用数据,直到 请求的金额,而不是等待收到全额 请求。
但这显然不是它在请求库中的工作方式。他们或多或少地将其用作“要接收的确切字节数”。 在查看他们的源代码时,我无法确定哪个部分对此负责。也许是 httplib 的 Response 或者 ssl 的 SSLSocket。
作为一种解决方法,我尝试将服务器上的行填充为块大小的倍数。 但是 requests-library 中的块大小用于从 压缩 响应流中获取字节。 因此,直到我可以填充我的行以使它们的 compressed 字节序列是块大小的倍数之前,这将不起作用。但这似乎太老套了。
我读到 Twisted 可用于客户端上的 http 流的非阻塞、非缓冲处理,但我只找到了用于在服务器上创建流响应的代码。
【问题讨论】:
-
你知道一个很好的框架/库来完成这项任务吗?库请求是题外话,恐怕。
-
对图书馆请求感到抱歉。如前所述,我目前正在使用 python-requests 并希望继续使用它。所以我的问题主要是关于如何用 python-requests 做事。但是:如果没有办法,我完全可以使用另一个库。
-
可以找线。底层压缩 zlib 支持使用的刷新 (Z_SYNC_FLUSH),当我在 GZipped 响应流上刷新 Tornado 中的响应时。因此,http 流非常好,被分割成完美的片段,其中包含完整的压缩行。仅仅用 Python 读回它们是很困难的。
-
我的分析不正确;我正在下面写更多信息。这不是
requests可以解决的限制。 -
我曾经做过类似的事情,基本上是去掉所有的套接字处理(特别是 socket.makefile)来正确处理缓冲区并使用 select() 从套接字增量读取内容。工作得很好,但这是一个正确的主要 PITA。基本上,一旦你得到响应,从响应中提取套接字并自己处理东西。这使 CPU 使用率从 90% 下降到 2%,并大大提高了吞吐量。 (但那是在古代 Python 2.2 中,2.7+ httplib 在分块编码方面做得更好)。
标签: python python-requests http-streaming