【问题标题】:Reading streaming http response with Python "requests" library使用 Python“请求”库读取流式 http 响应
【发布时间】:2015-03-24 04:56:01
【问题描述】:

我正在尝试使用Kubernetes 提供的事件流 使用requests 模块的api。我遇到了看起来像 缓冲问题:requests 模块似乎滞后了一个事件。

我的代码看起来像这样:

r = requests.get('http://localhost:8080/api/v1beta1/watch/services',
                 stream=True)

for line in r.iter_lines():
    print 'LINE:', line

由于 Kubernetes 发出事件通知,此代码将仅显示 新事件进入时发出的最后一个事件,这使得它 对于需要响应服务的代码几乎完全没用 添加/删除事件。

我已经通过在子进程中生成 curl 而不是使用 requests 库:

p = subprocess.Popen(['curl', '-sfN',
                      'http://localhost:8080/api/watch/services'],
                     stdout=subprocess.PIPE,
                     bufsize=1)

for line in iter(p.stdout.readline, b''):
    print 'LINE:', line

这可行,但会牺牲一些灵活性。有没有办法 避免requests 库的这种缓冲问题?

【问题讨论】:

    标签: python stream python-requests kubernetes


    【解决方案1】:

    此行为是由于 iter_lines 的错误实现 requests 库中的方法。

    iter_lines 迭代 chunk_size 块中的响应内容 使用iter_content 迭代器的数据。如果少于 chunk_size 可用于从远程读取的数据字节 服务器(通常在读取最后一行时会出现这种情况 输出),读操作将阻塞直到chunk_size字节 数据可用。

    我已经编写了自己的 iter_lines 例程,并且运行正常:

    import os
    
    
    def iter_lines(fd, chunk_size=1024):
        '''Iterates over the content of a file-like object line-by-line.'''
    
        pending = None
    
        while True:
            chunk = os.read(fd.fileno(), chunk_size)
            if not chunk:
                break
    
            if pending is not None:
                chunk = pending + chunk
                pending = None
    
            lines = chunk.splitlines()
    
            if lines and lines[-1]:
                pending = lines.pop()
    
            for line in lines:
                yield line
    
        if pending:
            yield(pending)
    

    这是可行的,因为os.read 将返回少于chunk_size 字节 而不是等待缓冲区填满。

    【讨论】:

    • 可以争论哪种实现是正确的——如果有更多数据可用,你的实现会插入一个假的“逻辑换行符”。正确的方法似乎是找出数据的总大小(指定一个是 TCP 通信的要求),并且只在已知端使用部分读取。
    • 我认为你不能争辩说现有的实现是正确的。我的没有经过严格的测试,但它确实工作得更好。一个更正确的实现——最好是作为上游补丁提交——会非常有用。
    • @ivan_pozdeev “正确的方法似乎是找出数据的总大小(指定一个是 TCP 通信的要求)” -- 不,TCP 是stream 并且可以有无限长。我不确定你是从哪里听说的,但这基本上是不真实的。
    • @JonathonReinhart 正因为如此,任何值得称道的 TCP 协议都要求发送者指定它要发送的每个数据块的长度。这就是我所说的“要求”。
    • @ivan_pozdeev “如果有更多数据可用,你的人会插入一个虚假的“逻辑换行符”” - 我认为这不是真的。如果这种方法没有一直读取到换行符,它会缓冲pending 中的尾随内容,直到读取下一个块。我认为这不会产生引入额外的换行符的效果,而该换行符并没有真正出现在响应中。你怎么认为这是可能的?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-03-22
    • 1970-01-01
    • 2010-12-17
    • 2015-12-17
    • 2020-05-13
    • 2012-08-10
    相关资源
    最近更新 更多