为什么ctypes调用的C库输出晚于执行它的Python代码?如何解决?
原因分析
这个现象的核心诱因是C标准库与Python运行时的标准输出缓冲区相互独立,二者的刷新策略不一致:
- 你调用的
hello_world属于C实现的函数,内部printf输出的内容会先写入C标准库的stdout缓冲区。默认情况下如果输出目标是终端,stdout为行缓冲,只有遇到换行符、缓冲区满、程序退出或主动调用fflush时才会把内容刷入终端;如果输出被重定向到文件/管道,stdout会变为全缓冲,刷新门槛更高。如果你的C代码的打印语句末尾没有换行符、或者处于全缓冲场景下,内容会暂时留在C的缓冲区中不会立即输出。 - Python的
print函数默认执行后会自动刷新自身的stdout缓冲区,所以内容会先显示在终端上。 - 程序退出前C标准库会自动刷新所有残留的缓冲区内容,因此C函数的打印内容最终会后于Python的打印输出,出现顺序颠倒。
解决方案
- 方案一:修改C动态库源码
在C函数内每次printf调用后增加fflush(stdout)主动刷新缓冲区,或者确保所有打印字符串末尾携带换行符(仅适用于输出到终端的行缓冲场景)。 - 方案二:Python侧调用后主动刷新C缓冲区
无需修改C库代码,通过ctypes调用C标准库的fflush接口刷新缓冲区,示例代码如下:from ctypes import * so_file = "./libtest.so.0" log = CDLL(so_file) # 加载系统libc库 libc = CDLL("libc.so.6") ret = log.hello_world(5) # 刷新所有C标准库的输出流 libc.fflush(None) print("print from python", ret) - 方案三:直接修改C标准库的stdout缓冲模式
加载动态库后先把C的stdout设置为无缓冲模式,后续所有C侧的打印都会立即输出:from ctypes import * so_file = "./libtest.so.0" log = CDLL(so_file) libc = CDLL("libc.so.6") # _IONBF是无缓冲标识,值为2,设置后stdout所有输出立即刷新 libc.setvbuf(libc.stdout, None, 2, 0) ret = log.hello_world(5) print("print from python", ret)
内容的提问来源于stack exchange,提问作者soroush
相关产品推荐
相关产品推荐

