非阻塞文件读取

max*_*max 6 python io python-3.x

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

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

读取和返回大小字节,或者如果未给出大小或为负,则直到EOF或读取调用将在非阻塞模式下阻塞.

显然,直截了当open(filename, 'rb').read()是阻塞模式.令我惊讶的是,我无法在io如何选择非阻塞模式的文档中找到任何解释.

对于文本文件:当我open(filename, mode='rt'),我得到io.TextIOWrapper.我假设相关的文档是read基类中的文档io.TextIOBase; 并根据这些文档,似乎没有办法做到无阻塞阅读所有:

从流中读取并返回最多大小字符作为单个str.如果大小为负或无,则读取直到EOF.

emo*_*ris 13

O_NONBLOCK通过设置标志,Python 确实支持非阻塞读取,至少在 Unix 类型系统上是这样。在 Python 3.5+ 中,有一个os.set_blocking()函数可以让这变得更容易:

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

然而,正如zvone 的回答所述,这不一定适用于实际的磁盘文件。但这不是 Python 的问题,而是操作系统的限制。正如 Linux open(2) 手册页所述:

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

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

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

  • 如果 os.set_blocking 不适合您(python < 3.5),请尝试 ```fcn​​tl.fcntl(f.fileno(), fcntl.F_SETFL, flag | os.O_NONBLOCK)``` (2认同)

zvo*_*one 9

文件操作正在阻塞.没有非阻塞模式.

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

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()
Run Code Online (Sandbox Code Playgroud)

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

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...
Run Code Online (Sandbox Code Playgroud)

  • 因此,文档中对非阻塞模式的引用仅适用于非文件流吗?有什么理由不能使文件读取无阻塞? (2认同)

Jug*_*aut 5

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

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

异步风格版本

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

  • 不太清楚你的 yield 语句应该进入什么上下文,你能提供一个更实用的例子吗? (3认同)