You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Linux下Python读写Named Pipes丢失文本行的问题排查与解决

命名管道(Named Pipes)进程间通信数据丢失问题排查与解决

我正在学习用命名管道实现进程间数据传递,写了两个Python脚本pipewriter.py和pipereader.py,通过mkfifo my_pipe创建了名为my_pipe的命名管道,所有文件均在同一目录下。

原脚本内容

pipewriter.py

#!/usr/bin/env python3
for i in range(1, 5):
  with open('my_pipe', 'a') as outfile:
    outfile.write(f'Hello {i}\n')
    if i==4:
      outfile.write('\n')

print('Done')

pipereader.py

#!/usr/bin/env python3
while True:
  with open('my_pipe', 'r') as infile:
    input = infile.read()
    print(input,end="")

问题现象

  • 单轮执行:在一个终端运行./pipereader.py,另一个终端运行./pipewriter.py,输出完整:
Hello 1
Hello 2
Hello 3
Hello 4
  • 多轮执行:运行./pipewriter.py; ./pipewriter.py; ./pipewriter.py(pipereader.py在另一个终端持续运行),输出偶尔会丢失部分行,例如:
Hello 1
Hello 2
Hello 3
Hello 1    <- 丢失"Hello 4"
Hello 2
Hello 3
Hello 4

Hello 1
Hello 2
Hello 3
Hello 4
  

尝试的修改

将pipewriter.py改为每次执行仅打开一次命名管道,似乎能避免丢失,但不确定是否只是降低了丢失频率而非彻底解决:

pipewriter.py(修改版)

#!/usr/bin/env python3 
with open('my_pipe', 'a') as outfile:
  for i in range(1, 5):
    outfile.write(f'Hello {i}\n')
  outfile.write('\n')

print('Done')

补充测试(带参数版本)

为更清晰定位问题,给pipewriter.py添加了命令行参数:

修改后的pipewriter.py(带参数)

#!/usr/bin/env python3
import sys

for i in range(1, 5):
  with open('my_pipe', 'a') as outfile:
    outfile.write(f'Hello {sys.argv[1]} {i}\n')
    if i==4:
      outfile.write('\n')

print('Done')

执行./pipewriter.py A; ./pipewriter.py B; ./pipewriter.py C的输出示例1:

Hello A 1
Hello A 2
Hello A 3
Hello A 4

Hello B 1
Hello B 2
Hello B 3
Hello B 4

Hello C 1
Hello C 2
Hello C 3

执行./pipewriter.py A; ./pipewriter.py B; ./pipewriter.py C的输出示例2:

Hello A 1
Hello A 2
Hello A 3
Hello A 4

Hello B 1
Hello B 2
Hello B 3
Hello B 4

Hello C 1
Hello C 2

问题原因分析

1. 命名管道的核心特性

命名管道是字节流而非消息队列,没有内置消息边界;同时,当所有打开管道的写端关闭时,读端的read()会返回EOF(空字符串)。

2. 原writer脚本的问题

原脚本在循环中每次打开、写入、关闭管道:

  • 每次循环结束关闭写端时,读端的infile.read()会收到EOF,返回已读取内容后退出当前with块,重新打开管道等待下一次写入。
  • 多次打开/关闭的间隙,可能出现写端关闭后、读端还未重新打开管道的窗口,此时新写端的写入数据会被遗漏;或者writer快速多次关闭/打开时,reader的read()可能在writer写入最后一行前就触发EOF,导致最后一行未被读取。

3. 修改后writer脚本的有效性

修改后的脚本全程保持管道写端打开,直到所有数据写入完成后才关闭:

  • 整个writer进程生命周期内写端始终打开,reader的read()会持续读取数据,直到writer关闭写端才收到EOF。
  • 这种方式消除了多次打开/关闭管道带来的EOF触发时机问题,是彻底解决数据丢失,而非降低频率。

额外的reader脚本优化

原reader脚本在while True循环中每次打开管道,可优化为保持读端持续打开,避免重复打开的开销和潜在间隙:

优化后的pipereader.py

#!/usr/bin/env python3
with open('my_pipe', 'r') as infile:
    while True:
        data = infile.readline()  # 按行读取更适配文本场景
        if not data:
            # 收到EOF时继续等待,因为可能有新writer打开管道
            continue
        print(data, end="")

内容的提问来源于stack exchange,提问作者Paul Wintz

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.04 13:55:56