Python 和 FIFO
我试图在 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 输入
和 mkfifo 输出
创建了两个 FIFO >。
我不明白的是为什么当我从两个控制台运行服务器(使用 python fifoserver.py 输入输出
)和客户端(使用 python fifoclient.py
)时某些请求导致客户端崩溃,并在 f.flush()
上出现“管道损坏”错误。请注意,在崩溃之前,我已经看到数百到数千个正确处理的请求运行良好。
我的代码有什么问题?
I was trying to understand FIFOs using Python under linux and I found a strange behavior i don't understand.
The following is 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")
and this is 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)))
I also created two FIFOs using mkfifo input
and mkfifo output
.
What I don't understand is why when I run the server (with python fifoserver.py input output
) and the client (with python fifoclient.py
) from two consoles after some requests the client crashes with a "broken pipe" error on f.flush()
. Note that before crashing I've seen from a few hundreds to several thousands correctly processed requests running fine.
What is the problem in my code?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
正如其他评论所提到的,你有一个竞争条件。
我怀疑在失败的情况下,服务器在以下行之一之后挂起:
然后客户端能够读取结果,将其打印到屏幕上,然后循环返回。然后它重新打开
f
- 它成功了,因为它在服务器端仍然打开 - 并写入消息。同时,服务器已成功关闭f
。接下来,客户端上的刷新在管道上执行write()
系统调用,这会触发SIGPIPE
,因为它现在在另一端已关闭。如果我是正确的,您应该能够通过将服务器的
f.close()
移动到g.write(...)
上方来修复它。As other comments have alluded to, you have a race condition.
I suspect that in the failing case, the server gets suspended after one of these lines:
The client is then able to read the result, print it to the screen, and loop back. It then reopens
f
- which succeeds, because it's still open on the server side - and writes the message. Meanwhile, the server has managed to closef
. Next, the flush on the client side executes awrite()
syscall on the pipe, which triggers theSIGPIPE
because it's now closed on the other side.If I'm correct, you should be able to fix it by moving the server's
f.close()
to be above theg.write(...)
.我不是 Unix 专家,但我的猜测是,您最终会在两个进程中关闭文件,然后打开写入。由于没有任何东西可以接受数据,管道破裂了。
我不明白为什么你总是打开和关闭管道。
尝试首先启动读取管道的进程,让它打开管道,然后它将等待数据。
然后启动管道编写器,让它泵出您想要发送的所有数据。如果它领先的话它就会停止。当写入器关闭管道时,读取器将获得零字节而不是阻塞,并且应该关闭。 IIRC,Python 检测到这一点并返回 EOF。
I am not a unix expert, but my guess is that you eventually end up with the file closed in both processes, and the open-for-write happens next. As there is nothing to accept the data, the pipe breaks.
I don't understand why you are opening and closing the pipe all the time.
Try starting the process that reads the pipe first, have it open the pipe and it will sit waiting for data.
Then start the pipe-writer, and have it pump out all the data you want to send. It will stall if it gets ahead. When the writer closes the pipe, the reader gets zero bytes instead of blocking, and should close. IIRC, Python detects this and returns EOF.