Python 管道 - 增量读取输出时会发生啥
Posted
技术标签:
【中文标题】Python 管道 - 增量读取输出时会发生啥【英文标题】:Python Pipes - What Happens When Reading Output IncrementallyPython 管道 - 增量读取输出时会发生什么 【发布时间】:2009-10-23 09:33:58 【问题描述】:根据a section中的this presumably accurate book,
管道的一个常见用途是读取 增量压缩文件;那 是,没有解压缩整个 一下子。以下函数 将压缩文件的名称作为 一个参数并返回一个管道 使用 gunzip 解压 内容:
def open_gunzip(filename): cmd = 'gunzip -c ' + filename fp = os.popen(cmd) return fp
如果你从 fp 中读取一行 时间,您永远不必存储 内存中或上的未压缩文件 磁盘。
也许我只是解释错了,但我不明白这怎么可能。 Python 无法在吐出结果的过程中暂停 gunzip,对吧?我假设 gunzip 在继续输出更多行之前读取一行输出之前不会阻塞,因此必须有一些缓冲区捕获所有这些(无论是在 Python 解释器中还是在操作系统中,无论是在内存中还是在磁盘上),这意味着未压缩的文件被完整地存储在某处...对吗?
【问题讨论】:
永远不要使用os.popen
。它已被弃用。请改用subprocess
模块。
【参考方案1】:
你的假设是错误的。 gunzip 不必查看整个文件即可解压缩它。阅读解压缩文件格式。有一个目录,其中包含各个组件的偏移量。
可以分段解压文件。
“未压缩的文件正在完整存储在某处......对吗?”
不一定。不知道你为什么假设它或你在哪里读到它。
所有低级 I/O 调用都可以阻塞。 gunzip 中的写入(写入管道时)可能会在管道缓冲区已满时阻塞。这就是定义管道 I/O 的方式。管道 I/O 块。
查看管道的手册页以获取详细信息。
如果一个进程试图从一个 空管道,然后 read(2) 将 阻塞直到数据可用。如果 一个进程尝试写入一个 满管(见下文),然后写(2) 阻塞直到有足够的数据 从管道中读取以允许 写完成。非阻塞 使用 fcntl(2) 可以实现 I/O F_SETFL 操作启用 O_NONBLOCK 打开文件状态标志。
【讨论】:
【参考方案2】:这真的来自gunzip
实现,而不是来自python。
它是用 C 编写的。它可能使用 C 的 stdio.h
中的 fwrite()
来编写它的输出。
libc6
实现我使用自动创建一个输出缓冲区,当它被填满时,阻塞fwrite()
,直到它可以写更多。
【讨论】:
关键是当gunzip
调用write()
时,阻塞发生在内核中。无论您的程序是用 C 还是 Python 编写的,甚至根本使用 libc,都会发生这种情况。【参考方案3】:
暂停gunzip
的不是Python,而是内核在尝试写入(使用write()
系统调用)到完整缓冲区时将停止执行gunzip
。这称为阻塞 IO。内核维护一个连接管道两端的内部缓冲区,独立于任何正在写入或读取管道的进程中发生的任何缓冲。
当从具有空缓冲区(即当前没有来自gunzip
的任何数据写入其中)的管道读取数据时,Python 也会同样阻塞。
管道可以看作是Producer-consumer problem 的解决方案。
【讨论】:
以上是关于Python 管道 - 增量读取输出时会发生啥的主要内容,如果未能解决你的问题,请参考以下文章
Databricks - 从增量表写入流到 orc 文件的读取流仅具有更改