Python 3.x Python通过对命名管道的非阻塞写入避免部分写入
我正在linux上运行python3.8 在脚本中,我创建了一个命名管道,并按如下方式打开它:Python 3.x Python通过对命名管道的非阻塞写入避免部分写入,python-3.x,file-io,posix,Python 3.x,File Io,Posix,我正在linux上运行python3.8 在脚本中,我创建了一个命名管道,并按如下方式打开它: import os import posix import time file_name = 'fifo.txt' os.mkfifo(file_name) f = posix.open(file_name, os.O_RDWR | os.O_NONBLOCK) os.set_blocking(f, False) 在没有打开该文件以便在其他地方读取(例如,使用cat)的情况下,我开始循环写入该文
import os
import posix
import time
file_name = 'fifo.txt'
os.mkfifo(file_name)
f = posix.open(file_name, os.O_RDWR | os.O_NONBLOCK)
os.set_blocking(f, False)
在没有打开该文件以便在其他地方读取(例如,使用cat
)的情况下,我开始循环写入该文件
base_line = 'abcdefghijklmnopqrstuvwxyz'
s = base_line * 10000 + '\n'
while True:
try:
posix.write(f, s.encode())
except BlockingIOError as e:
print("Exception occurred: {}".format(e))
time.sleep(.5)
然后,当我使用cat
读取命名管道时,我发现发生了部分写入
我很困惑如何知道在这个实例中写入了多少字节。由于引发了异常,我无法访问返回值(写入的字节数)。文档表明BlockingIOError
有一个名为characters\u writed
的属性,但是当我尝试访问此字段时,会引发AttributeError
总而言之:首先,我如何避免这种部分写入,或者至少知道在这种情况下有多少部分写入?
os.write
执行无缓冲写入。文档说明当缓冲写入操作将被阻塞时,BlockingIOError
仅具有characters\u writed
属性
如果在管道满之前成功写入了任何字节,那么将从os.write
返回该字节数。否则,您将得到一个异常。当然,驱动器故障之类的情况也会导致异常,即使写入了一些字节。这与POSIXwrite
的工作方式没有什么不同,只是在出错时没有返回-1,而是引发了异常
如果不喜欢处理异常,可以在文件描述符周围使用包装器,例如io.FileIO
对象。我修改了您的代码,因为每次您循环回操作系统时,它都会尝试写入整个缓冲区。write调用(如果失败一次,每次都会失败):
您还可以在的答案中找到一些有用的信息。谢谢您的回复。我间接地从中得到了答案:)。我假设引发写入调用的第一个异常是部分写入。事实上,部分写入是完全有效的(检查显示的长度是正确的)。在其余部分,休眠而不是选择器用于演示代码。实际上,此代码是更大的执行循环的一部分。再次感谢!
import io
import os
import time
base_line = 'abcdefghijklmnopqrstuvwxyz'
data = (base_line * 10000 + '\n').encode()
file_name = 'fifo.txt'
os.mkfifo(file_name)
fd = os.open(file_name, os.O_RDWR | os.O_NONBLOCK)
# os.O_NONBLOCK makes os.set_blocking(fd, False) unnecessary.
with io.FileIO(fd, 'wb') as f:
written = 0
while written < len(data):
n = f.write(data[written:])
if n is None:
time.sleep(.5)
else:
written += n
with io.FileIO(fd, 'wb') as f:
written = 0
sel = selectors.DefaultSelector()
sel.register(f, selectors.EVENT_WRITE)
while written < len(data):
n = f.write(data[written:])
if n is None:
# Wait here until we can start writing again.
sel.select()
else:
written += n
sel.unregister(f)