Python 和 FIFO

发布于 2024-10-18 20:55:20 字数 1252 浏览 8 评论 0原文

我试图在 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

煞人兵器 2024-10-25 20:55:21

正如其他评论所提到的,你有一个竞争条件。

我怀疑在失败的情况下,服务器在以下行之一之后挂起:

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

然后客户端能够读取结果,将其打印到屏幕上,然后循环返回。然后它重新打开 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:

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

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 close f. Next, the flush on the client side executes a write() syscall on the pipe, which triggers the SIGPIPE 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 the g.write(...).

回心转意 2024-10-25 20:55:21

我不是 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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文