Python调用C可执行程序stdout的readline()时出现异常延迟问题求助
Python调用C可执行程序stdout的readline()时出现异常延迟问题求助
看起来你遇到的这个延迟问题确实挺闹心的,结合你描述的现象——第一次读取卡20-30秒,后续正常但每40次左右又卡一次——我觉得大概率和C程序的stdout缓冲策略有关,下面给你梳理下可能的原因和对应的解决思路:
核心原因分析:C程序的stdout缓冲在非终端环境下会变化
你提到C程序里的printf都带了\n,理论上在终端运行时,stdout是行缓冲模式,遇到\n就会自动刷新缓冲区输出。但当C程序被Python的Popen调用时,stdout并不是直接连接到终端,而是被重定向到了管道(Python的subprocess.PIPE),这时候C的stdout默认会切换成全缓冲模式——也就是只有当缓冲区被填满(通常是4KB或8KB级别),或者程序主动调用fflush时,才会把缓冲的内容输出到管道里。
这就完美解释了你的现象:第一次卡是因为要等C程序的全缓冲区填满才输出,后续快是因为缓冲区里还有残留内容可以读取,每40次左右又卡一次,刚好对应缓冲区又被填满一轮的节奏。
解决办法:从C程序或Python端强制行缓冲
方法1:修改C程序,强制设置行缓冲(最推荐)
直接在C程序的开头(比如main函数第一行)添加一行代码,强制stdout始终使用行缓冲模式,不管输出目标是不是终端:
#include <stdio.h> int main() { // 强制stdout为行缓冲,参数分别是:流、缓冲区(NULL用系统默认)、缓冲模式、缓冲区大小 setvbuf(stdout, NULL, _IOLBF, 0); // 你的原有代码... printf("your output line\n"); // 不需要额外fflush,行缓冲下\n会自动触发刷新 }
如果不想全局修改缓冲模式,也可以在每次printf之后手动调用fflush(stdout);来强制刷新:
printf("your output line\n"); fflush(stdout); // 强制把缓冲内容输出到管道
方法2:Python端配合调整缓冲设置
如果暂时没法修改C程序,可以试试在Python的Popen里明确设置缓冲模式和文本模式,让Python端的管道读取和C程序的输出节奏匹配:
import subprocess import time # text=True(Python3.7+)等价于universal_newlines=True,bufsize=1代表行缓冲 proc = subprocess.Popen(["PATH TO EXECUTABLE"], stdout=subprocess.PIPE, text=True, bufsize=1) # 用iter简化循环,避免手动while True的潜在问题 for line in iter(proc.stdout.readline, ''): start_time = time.time() print(line.strip()) print(f"耗时:{time.time() - start_time:.6f}秒")
额外排查建议
- 验证C程序的缓冲行为:直接在树莓派终端执行
./your_executable > output.txt,然后观察output.txt是不是实时有内容写入。如果要等很久才会有内容,那完全可以确认是C程序的全缓冲问题。 - 检查C程序的输出内容:有没有某些行特别长,或者偶尔没有输出
\n的情况?如果有没加\n的输出,行缓冲也不会触发刷新,同样会导致缓冲积累。 - 排除树莓派进程调度问题:如果以上方法都没用,可以试试给Python进程提优先级(比如用
nice命令),不过这个概率很低,因为你的延迟是规律性的,更像缓冲问题。
内容来源于stack exchange
相关产品推荐
相关产品推荐

