Python是否支持异步文件写入?

23

有没有一种简单的方法在Python中异步写入文件?

我知道Python自带的文件IO是阻塞式的,在大多数情况下这是可以接受的。但对于特定情况,我需要尽可能地减少写入对应用程序的阻塞甚至完全不阻塞。

5个回答

19

据我所知,异步 I/O 与非阻塞 I/O 不完全相同。

在非阻塞 I/O 的情况下,一旦设置文件描述符为“非阻塞”,例如进行 read() 系统调用时,如果读操作将会阻塞调用进程才能完成操作,则会返回 EWOULDBLOCK(或 EAGAIN)。提供了 select()poll()epoll()等系统调用,以便进程可以请求操作系统告知一个或多个文件描述符何时变得可用,以执行某些 I/O 操作。

异步 I/O 是通过将 I/O 请求排队到文件描述符中独立地跟踪来实现的。对于支持异步 I/O 的文件描述符(通常是原始磁盘设备),进程可以调用 aio_read() 来请求从文件描述符中读取一定数量的字节。无论 I/O 是否完成,该系统调用都会立即返回。稍后,进程则轮询操作系统以获取 I/O 的完成情况(也就是缓冲区中填充了数据)。

一个只执行非阻塞 I/O 的进程(单线程)将能够在一个文件描述符准备好进行 I/O 时从中读取或写入,而另一个未准备好。但是,该进程仍必须同步发出系统调用以对所有准备好的文件描述符执行 I/O。相比之下,在异步 I/O 的情况下,该进程只是检查 I/O 是否完成(缓冲区是否填充了数据)。使用异步 I/O,如果操作系统选择这样做,它就可以尽可能并行地运行以服务 I/O。
因此,是否有 POSIX aio_read/write 等 Python 系统调用的包装器?

有一件事需要补充:正如第一个回复中的评论者所说,没有系统实际上在文件上使用 O_NONBLOCK-它只适用于套接字。如果您想在Unix上进行可移植异步文件IO,则必须使用 POSIX AIO 或将同步IO卸载到线程池中。 - Conrad Meyer

5

13
遗憾的是,O_NONBLOCK(这就是您链接的fdesc API实际上所做的)无法与本地硬盘文件一起使用。也就是说,POSIX规范规定应该忽略它,在我知道的每个UNIX系统上都会被忠实地忽略。如果您认为这是一个愚蠢的想法,我完全同意,但有许多历史和实现原因导致了这种情况。简而言之,如果您想要对本地硬盘文件进行异步IO操作,最好使用线程并将IO操作延迟到IO线程中,或者使用AIO API。 - mathieu

4
您可以尝试使用Thread
from threading import Thread

for file in list_file:
     tr = Thread(target=file.write, args=(data,))
     tr.start()

这更像是伪代码,但我希望你能理解。请注意,这里的线程是保持打开状态。

根据我的经验,它运行得很好,尽管解释器在主脚本完成后仍然需要一些时间才能工作(需要使用 join()),因此速度提升并不像看起来那么大。


2
我正在开发将aio.h绑定到Python的pyaio:pyaio
它只能在Linux上运行。

0

Python 3似乎具有这样的功能。请参见PEP 3116


1
看起来PEP 3116与包括非阻塞I/O的新I/O抽象有关。然而,非阻塞I/O并不等同于异步I/O。非阻塞I/O通常不适用于本地文件系统写入。 - Robie Basak

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接