Python与FIFO

6 投票
2 回答
6750 浏览
提问于 2025-04-16 12:20

我在Linux上用Python尝试理解FIFO(先进先出)的时候,发现了一些奇怪的行为,搞不懂。

下面是 fifoserver.py 的内容:

import sys
import time

def readline(f):
    s = f.readline()
    while s == "":
        time.sleep(0.0001)
        s = f.readline()
    return s

while True:
    f = open(sys.argv[1], "r")
    x = float(readline(f))
    g = open(sys.argv[2], "w")
    g.write(str(x**2) + "\n")
    g.close()
    f.close()
    sys.stdout.write("Processed " + repr(x) + "\n")

而这是 fifoclient.py 的内容:

import sys
import time

def readline(f):
    s = f.readline()
    while s == "":
        time.sleep(0.0001)
        s = f.readline()
    return s

def req(x):
    f = open("input", "w")
    f.write(str(x) + "\n")
    f.flush()
    g = open("output", "r")
    result = float(readline(g))
    g.close()
    f.close()
    return result

for i in range(100000):
    sys.stdout.write("%i, %s\n" % (i, i*i == req(i)))

我还用 mkfifo inputmkfifo output 创建了两个FIFO。

我不明白的是,当我在两个控制台中分别运行服务器(用 python fifoserver.py input output)和客户端(用 python fifoclient.py)时,经过一段请求后,客户端会因为“管道破裂”的错误在 f.flush() 这行崩溃。值得注意的是,在崩溃之前,我看到有几百到几千个请求都处理得很好。

我的代码中到底出了什么问题呢?

2 个回答

0

我不是Unix方面的专家,但我猜最后你会发现两个进程都把文件关掉了,然后才开始写入。因为没有地方可以接收数据,所以管道就断了。

我不明白你为什么总是打开和关闭管道。

试着先启动读取管道的进程,让它打开管道并等待数据到来。

然后再启动写入管道的进程,让它把你想发送的所有数据都写出去。如果写入的速度太快,它会停下来。当写入者关闭管道时,读取者会收到零字节的数据,而不是一直等待,这样它就应该关闭了。如果我没记错的话,Python会检测到这一点并返回EOF(文件结束)。

5

正如其他评论提到的,你遇到了一个竞争条件的问题。

我猜在出错的情况下,服务器在执行以下某一行代码后会被暂停:

g.write(str(x**2) + "\n")
g.close()

然后,客户端可以读取结果,把它打印到屏幕上,并且重新开始循环。接着,它重新打开了 f,这时成功了,因为服务器那边的 f 仍然是打开的。然后客户端写入消息。与此同时,服务器已经关闭了 f。接下来,客户端的刷新操作执行了一个 write() 系统调用到管道,这时因为另一边已经关闭,所以会触发 SIGPIPE 错误。

如果我说的没错,你可以通过把服务器的 f.close() 移到 g.write(...) 之前来解决这个问题。

撰写回答