【问题标题】:Python HTTP client with request pipelining带有请求管道的 Python HTTP 客户端
【发布时间】:2018-03-28 04:17:26
【问题描述】:

问题:我需要向服务器发送许多 HTTP 请求。我只能使用一个连接(不可协商的服务器限制)。服务器的响应时间加上网络延迟太高——我落后了。

请求通常不会更改服务器状态,也不依赖于先前请求的响应。所以我的想法是简单地将它们相互叠加发送,将响应对象排入队列,并依赖传入响应的 Content-Length: 来将传入响应提供给下一个等待的响应对象。换句话说:将请求传送到服务器。

这当然不是完全安全的(任何没有 Content-Length: 的回复都意味着麻烦),但我不在乎——在这种情况下,我总是可以重试任何排队的请求。 (安全的方法是在发送下一个位之前等待标头。这可能对我有足够的帮助。没有办法事先测试。)

因此,理想情况下,我希望以下客户端代码(使用客户端延迟来模拟网络延迟)在三秒内运行。

现在是 64000 美元的问题:是否有 Python 库已经做到了这一点,还是我需要自己开发?我的代码使用 gevent;如有必要,我可以使用 Twisted,但 Twisted 的标准连接池不支持流水线请求。如有必要,我也可以为某些 C 库编写一个包装器,但我更喜欢本机代码。

#!/usr/bin/python

import gevent.pool
from gevent import sleep
from time import time

from geventhttpclient import HTTPClient

url = 'http://local_server/100k_of_lorem_ipsum.txt'
http = HTTPClient.from_url(url, concurrency=1)

def get_it(http):
    print time(),"Queueing request"
    response = http.get(url)
    print time(),"Expect header data"
    # Do something with the header, just to make sure that it has arrived
    # (the greenlet should block until then)
    assert response.status_code == 200
    assert response["content-length"] > 0
    for h in response.items():
        pass

    print time(),"Wait before reading body data"
    # Now I can read the body. The library should send at
    # least one new HTTP request during this time.
    sleep(2)
    print time(),"Reading body data"
    while response.read(10000):
        pass
    print time(),"Processing my response"
    # The next request should definitely be transmitted NOW.
    sleep(1)
    print time(),"Done"

# Run parallel requests
pool = gevent.pool.Pool(3)
for i in range(3):
    pool.spawn(get_it, http)

pool.join()
http.close()

【问题讨论】:

  • 注意:至于 C 库,我已经在 code.google.com/p/serf 找到了 serf。不幸的是,为 that 库编写工作 Python 绑定并不是我目前支付的费用。 :-/
  • 您的代码看起来有点像grequests 所做的。你看过了吗?如果你有,你能解释为什么它不适合吗? (我可能还没有完全理解这个问题)
  • grequests 是一个简单的请求异步包装器,即每个请求一个线程,每个请求仍然是使用自己的连接的发送/接收/发送下一个位锁步。我需要打开一个 TCP 连接,然后生成一个发送请求标头的线程,另一个接收响应并将它们与“他们的”请求相关联的东西。
  • 这个例子(code.activestate.com/recipes/576673-python-http-pipelining)效果很好。但仅在 Python2 中 - 如果它转换为 Python3,它仅适用于 50% 的情况......
  • 一个更有趣的事情是让你的服务器支持 http/2,然后使用类似 grpc 或 hyper 的东西。

标签: python http streaming


【解决方案1】:

Dugong 是一个仅支持 HTTP/1.1 的客户端,声称支持真正的 HTTP/1.1 流水线。 The tutorial 包含几个关于如何使用它的示例,包括一个 using threads 和另一个 using asyncio

请务必确认您正在与之通信的服务器确实支持 HTTP/1.1 流水线 - 一些服务器声称支持 HTTP/1.1 但未实现流水线。

【讨论】:

    【解决方案2】:

    我认为 txrequests 可以为您提供所需的大部分内容,使用 background_callback 在单独的线程上对响应进行排队处理。每个请求仍然是它自己的线程,但使用会话意味着默认情况下它会重用相同的连接。

    https://github.com/tardyp/txrequests#working-in-the-background

    【讨论】:

      【解决方案3】:

      看来你正在运行 python2。

      对于 python3 >= 3.5 你可以使用异步/等待循环 见asyncio

      此外,还有一个构建在上面的库,可以更好、更轻松地使用 称为Trio,在 pip 上可用。


      我能想到的另一件事是带锁的多个线程。 我会考虑如何更好地解释这一点,或者它甚至可以工作。

      【讨论】:

      • 请说明哪个异步 HTTP 库能够将多个请求排队到单个连接上。 aiohttp 做不到。
      • 分析器与流水线无关
      • aiohttp 可能会在 ClientSession: github.com/aio-libs/aiohttp/issues/1740 中添加请求管道
      猜你喜欢
      • 2017-01-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-05-10
      • 2017-04-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多