如何使用非阻塞IO写入文件?

17 投票
2 回答
27831 浏览
提问于 2025-04-17 12:57

我想用一种非阻塞的方法在Python中写入文件。经过一些搜索,我发现这个语言支持使用fcntl来实现这个功能,但具体怎么做我还不太明白。

这是我写的代码片段(我不知道哪里出错了):

import os, fcntl
nf = fcntl.fcntl(0,fcntl.F_UNCLK)
fcntl.fcntl(0,fcntl.F_SETFL , nf | os.O_NONBLOCK )
nf = open ("test.txt", 'a') 
nf.write ( " sample text \n")

这样做是正确的非阻塞文件操作吗?我有点怀疑。另外,你能推荐一些Python中的其他模块让我实现这个功能吗?

2 个回答

4

操作系统会把写入的数据暂时存储在缓存中,然后在几秒钟后再写入到硬盘上。也就是说,这个过程本身就是“非阻塞”的,你不需要做什么特别的操作。

19

这是在UNIX系统中如何为文件开启非阻塞模式的方法:

fd = os.open("filename", os.O_CREAT | os.O_WRONLY | os.O_NONBLOCK)
os.write(fd, "data")
os.close(fd)

不过在UNIX上,开启非阻塞模式对普通文件没有明显的效果!即使文件处于非阻塞模式,os.write 的调用也不会立刻返回,它会一直等到写入完成才会继续。你可以通过实验来验证这一点,试试这个:

import os
import datetime

data = "\n".join("testing\n" * 10 for x in xrange(10000000))
print("Size of data is %d bytes" % len(data))

print("open at %s" % str(datetime.datetime.now()))
fd = os.open("filename", os.O_CREAT | os.O_WRONLY | os.O_NONBLOCK)
print("write at %s" % str(datetime.datetime.now()))
os.write(fd, data)
print("close at %s" % str(datetime.datetime.now()))
os.close(fd)
print("end at %s" % str(datetime.datetime.now()))

你会发现 os.write 的调用确实需要几秒钟。虽然这个调用是非阻塞的(从技术上讲,它并不是阻塞,而是在等待),但这个调用并不是异步的。


据我所知,在Linux或Windows上没有办法异步写入文件。不过,你可以通过使用线程来模拟这种效果。Twisted有一个叫做 deferToThread 的方法可以实现这个目的。下面是它的用法:

from twisted.internet import threads, reactor

data = "\n".join("testing\n" * 10 for x in xrange(10000000))
print("Size of data is %d bytes" % len(data))

def blocking_write():
    print("Starting blocking_write")
    f = open("testing", "w")
    f.write(data)
    f.close()
    print("End of blocking_write")

def test_callback():
    print("Running test_callback, just for kicks")

d = threads.deferToThread(blocking_code)
reactor.callWhenRunning(cc)
reactor.run()

撰写回答