PyFile_WriteObject写入时机过晚问题咨询及代码示例
解决PyFile_WriteObject写入时机过晚的问题
我之前也碰到过类似的坑,你遇到的这个问题核心是Python的stdout对象自带独立的缓冲机制,和C标准库printf的缓冲不是一回事,两者的输出刷新时机不一致,就会显得PyFile_WriteObject的内容“迟到”了。
先把你的代码贴出来方便分析:
PyObject* py_list(PyObject* obj) { printf("py_list: %p, ", obj); PyObject* pystdout = PySys_GetObject("stdout"); PyFile_WriteObject(obj, pystdout, Py_PRINT_RAW); printf("\n"); printf("py_list: %p\n", pystdout); if (obj == NULL) { return PyList_New(0); } PyObject* result = PyList_New(1); PyList_SetItem(result, 0, obj); printf("py_list returns: %p, ", result); PyFile_WriteObject(result, pystdout, Py_PRINT_RAW); printf("\n"); return result; }
问题根源
Python的sys.stdout默认是行缓冲模式(终端环境下),如果是非终端环境甚至是全缓冲。PyFile_WriteObject把内容写入到这个缓冲区后,并不会立刻刷新到终端;而printf用的是C标准库的缓冲,遇到\n就会触发行缓冲刷新。两者的刷新节奏不一样,自然会出现输出顺序错位的情况。
直接解决办法
最靠谱的方案就是在每次调用PyFile_WriteObject之后,手动刷新Python的stdout缓冲区,用PyFile_Flush函数即可:
修改后的代码示例:
PyObject* py_list(PyObject* obj) { printf("py_list: %p, ", obj); PyObject* pystdout = PySys_GetObject("stdout"); // 先检查stdout是否有效 if (pystdout == NULL || !PyFile_Check(pystdout)) { PyErr_SetString(PyExc_RuntimeError, "stdout is not a valid file object"); return NULL; } PyFile_WriteObject(obj, pystdout, Py_PRINT_RAW); // 手动刷新Python stdout缓冲区 PyFile_Flush(pystdout, NULL); printf("\n"); printf("py_list: %p\n", pystdout); if (obj == NULL) { return PyList_New(0); } PyObject* result = PyList_New(1); PyList_SetItem(result, 0, obj); printf("py_list returns: %p, ", result); PyFile_WriteObject(result, pystdout, Py_PRINT_RAW); // 同样刷新缓冲区 PyFile_Flush(pystdout, NULL); printf("\n"); return result; }
其他可选思路
- 如果你愿意改用Python的
print函数(通过C API调用),可以构造print调用并指定flush=True,比如用PyRun_SimpleString("print(obj, flush=True)")(需要适配你的变量),这样Python会自动处理刷新逻辑。 - 极端情况下可以修改
sys.stdout的缓冲模式,用PyFile_SetBufSize把缓冲区设为0(无缓冲),但这种方式会影响整个程序的stdout输出性能,除非必要不推荐。
内容的提问来源于stack exchange,提问作者wvx
相关产品推荐
相关产品推荐

