【问题标题】:Non-blocking file read非阻塞文件读取
【发布时间】:2017-02-18 07:16:47
【问题描述】:

如何在非阻塞模式下读取二进制文件或文本文件的内容?

对于二进制文件:当我open(filename, mode='rb') 时,我得到一个io.BufferedReader 的实例。文档堡垒io.BufferedReader.readsays

读取并返回 size 字节,或者如果 size 没有给出或为负数,直到 EOF 或 read 调用将在非阻塞模式下阻塞。

很明显,一个简单的open(filename, 'rb').read() 处于阻塞模式。令我惊讶的是,我在io 文档中的任何地方都找不到关于如何选择非阻塞模式的解释。

对于文本文件:当我open(filename, mode='rt') 时,我得到io.TextIOWrapper。我假设相关文档是read 在其基类io.TextIOBase 中的文档;和according to those docs,似乎根本没有办法进行非阻塞读取:

从流中读取并返回最多 size 个字符作为单个 str。如果 size 为负数或 None,则读取直到 EOF。

【问题讨论】:

  • 不确定是否需要使用os.O_NONBLOCK在较低级别执行此操作
  • 请告诉我你为什么不赞成我的回答?无关紧要吗?
  • @Amin Etesamian 我没有投反对票,我不确定为什么其他阅读它的人不喜欢它。似乎相关,虽然我不知道 aiofiles 库。
  • @max 我在异步文件服务服务中使用了它。效果很好。

标签: python python-3.x io


【解决方案1】:

我建议使用aiofiles - 一个用于在异步应用程序中处理本地磁盘文件的库。

f = yield from aiofiles.open('filename', mode='r')
try:
    contents = yield from f.read()
finally:
    yield from f.close()
print(contents)
'My file contents'

异步风格版本

async def read_without_blocking():
    f = await aiofiles.open('filename', mode='r')
    try:
        contents = await f.read()
    finally:
        await f.close()

【讨论】:

  • 不太清楚你的收益语句应该进入什么上下文,你能提供一个更实用的例子吗?
  • 如何调用异步函数?我收到一个错误,即未等待该功能。如何从同步函数中调用异步函数?
  • @Juggernaut 很抱歉,仍然不清楚如何使用上述代码。您能否编辑您的代码以包含示例执行
【解决方案2】:

文件操作被阻塞。没有非阻塞模式。

但是你可以创建一个线程在后台读取文件。在 Python 3 中,concurrent.futures module 在这里很有用。

from concurrent.futures import ThreadPoolExecutor

def read_file(filename):
    with open(filename, 'rb') as f:
        return f.read()

executor = concurrent.futures.ThreadPoolExecutor(1)
future_file = executor.submit(read_file, 'C:\\Temp\\mocky.py')

# continue with other work

# later:

if future_file.done():
    file_contents = future_file.result()

或者,如果您需要在操作完成时调用回调:

def on_file_reading_finished(future_file):
    print(future_file.result())

future_file = executor.submit(read_file, 'C:\\Temp\\mocky.py')
future_file.add_done_callback(on_file_reading_finished)

# continue with other code while the file is loading...

【讨论】:

  • 那么文档中对非阻塞模式的引用只适用于非文件流?文件读取不能非阻塞是否有原因?
【解决方案3】:

Python 确实支持非阻塞读取,至少在 Unix 类型系统上,通过设置 O_NONBLOCK flag。在 Python 3.5+ 中,os.set_blocking() function 使这更容易:

import os
f = open(filename, 'rb')
os.set_blocking(f.fileno(), False)
f.read()  # This will be non-blocking.

然而,正如zvone's answer 所说,这不一定适用于实际的磁盘文件。不过,这不是 Python 的事情,而是操作系统的限制。正如 Linux open(2) man page 所说:

请注意,此标志对常规文件和块设备无效; 也就是说,当设备活动停止时,I/O 操作将(短暂)阻塞 必需,无论是否设置了 O_NONBLOCK。

但它确实表明这可能会在未来实施:

由于 O_NONBLOCK 语义最终可能会实现, 应用程序在指定时不应依赖于阻塞行为 此标志用于常规文件和块设备。

【讨论】:

  • 如果您无法使用 os.set_blocking (python fcntl.fcntl(f.fileno(), fcntl.F_SETFL, flag | os.O_NONBLOCK)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-07-09
  • 2014-11-17
  • 1970-01-01
  • 2015-05-05
相关资源
最近更新 更多