【问题标题】:How to stream data in python without loading it all into memory at once?如何在python中流式传输数据而不一次将其全部加载到内存中?
【发布时间】:2021-05-18 20:15:56
【问题描述】:

我正在尝试写入和读取流而不是一次将所有内容加载到内存中。这是我想象的工作:

import io

stream = io.BytesIO()

def process_stream(stream):
  while True:
    chunk = stream.read(5).decode('utf-8')
    if not chunk:
      return
    yield chunk

# this would be a separate thread, but here we just do it in serial:
for i in range(3):
  stream.write(b'asdf')

for chunk in process_stream(stream):
  print('I read', chunk)

但这实际上并没有打印出任何东西。 我可以让它工作,但只有以下两个更改,其中任何一个都需要一次将所有字节保存在内存中:

  • 初始化 stream = io.BytesIO(b'asdf' * 3) 而不是增量写入
  • 使用stream.getvalue() 而不是增量读取

我很困惑增量写入只能通过批量读取来读取,而增量读取仅适用于批量写入。如何获得一个恒定内存(假设 process_stream 超过写作)的解决方案?

【问题讨论】:

标签: python io


【解决方案1】:

当您使用 for 循环写入流时。您的搜索最终位于最后一个位置。

asdfasdfasdf|
            ^ (Seek)            

因此,当您尝试阅读时,最后一个字符之后没有任何内容,因此在阅读流时您什么也得不到。一种解决方案是将搜索重新定位到流的开头,以便您可以阅读它。为此我们可以使用stream.seek(0)

|asdfasdfasdf
^ (Seek after calling stream.seek(0))            

代码:

import io

stream = io.BytesIO()


def process_stream(stream, chunk_size=5):
    while True:
        chunk = stream.read(chunk_size).decode('utf-8')
        if not chunk:
            return
        yield chunk


# this would be a separate thread, but here we just do it in serial:
for i in range(3):
    stream.write(b'asdf')

stream.seek(0) # Reset the seek so it is at the beginning
for chunk in process_stream(stream):
    print('I read', chunk)

输出:

I read asdfa
I read sdfas
I read df

更多信息:How the write(), read() and getvalue() methods of Python io.BytesIO work?

【讨论】:

  • 这有帮助,但我仍在寻找一个恒定内存的解决方案。似乎每当调用.write 时,光标都会再次移动到流的末尾。例如,如果我写'a',寻找0,读,写'b',读,我得到''。如果我在写完“b”后再次寻找 0,我会得到“ab”。我正在寻找一种解决方案,其中第二次读取只给出“b”,剩余的未读字节,“a”从内存中释放。 BytesIO 不是正确的工具吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-09-11
  • 1970-01-01
  • 2015-02-27
  • 1970-01-01
  • 2011-07-01
  • 1970-01-01
相关资源
最近更新 更多