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

17
我希望在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")

这是在文件上执行非阻塞IO操作的正确方法吗?我对此表示怀疑。此外,你能否建议一些其他的Python模块来实现非阻塞IO操作?


可能是Python中是否可以进行异步文件写入?的重复问题。 - jcollado
不,不是这样的,我需要保持简单,只使用fcntl :) - Rahul
2个回答

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()

我该如何从由服务器工厂构建的LineReciver或其他类似协议中访问反应堆对象? - Sean
可以使用POSIX AIO或Windows IOCP对常规文件进行非阻塞写入。 - strcat

4

操作系统会缓存写入内容,并在几秒钟后将其转储到磁盘上。也就是说,它们已经“非阻塞”了。您不需要做任何特殊的事情。


1
如果文件实际上挂载在网络共享上怎么办?当然,只有在收到确认后,调用才会返回。 - Flimm
1
根据远程文件系统和实现的语义,可能是同步或异步的。有两种示例,甚至有像“关闭同步”这样的东西。 - jcea

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