Python "print"嵌入到 MPI 程序中时不起作用
Python "print" not working when embedded into MPI program
我在C++MPI应用程序中嵌入了一个Python 3解释器。此应用程序加载一个脚本并将其传递给解释器。
当我在没有MPI启动器的情况下(只需调用./myprogram)在1个进程上执行程序时,脚本会正确执行,其"打印"语句会输出到终端。当脚本出现错误时,我会使用PyErr_print()在C++端打印它。
然而,当我通过mpirun启动程序时(即使是在单个进程上),我也不会从python代码中的"print"获得任何输出。当我的脚本出现错误时,我也不会从PyErr_Print()中得到任何东西。
我想Python处理标准输出的方式与MPI(此处为actall-Mpich)处理将进程的输出重定向到启动器并最终重定向到终端的方式不匹配。
你知道怎么解决这个问题吗?
[编辑,遵循本期建议]
每次调用PyErr_Print
后,您需要flush_io()
,其中flush_io
可以是以下函数:
void flush_io(void)
{
PyObject *type, *value, *traceback;
PyErr_Fetch(&type, &value, &traceback); // in Python/pythonrun.c, they save the traceback, let's do the the same
for (auto& s: {"stdout", "stderr"}) {
PyObject *f = PySys_GetObject(s);
if (f) PyObject_CallMethod(f, "flush", NULL);
else PyErr_Clear();
}
PyErr_Restore(type, value, traceback);
}
[在我的旧分析下面,它仍然有一些有趣的信息]
我最终遇到了同样的问题(PyErr_Print
无法从mpirun中运行)。追溯(涉及python3的一些gdb),并比较工作的东西(./myprogram)和不工作的事情(mpirun-np 1./myprogram),我最终在./Modules/_io/textio.c:1277
的_io_TextIOWrapper_write_impl
(顺便说一句,python-3.60)。
两次运行之间的唯一区别是self->line_buffering
是1对0(此时self
表示sys.stderr
)。然后,在pylifecycle.c:1128
中,我们可以看到是谁决定了这个值:
if (isatty || Py_UnbufferedStdioFlag)
line_buffering = Py_True;
因此,MPI似乎在启动程序之前对stderr做了一些事情,这使得它不是tty。我还没有调查mpirun中是否有将tty标志保留在stderr上的选项。。。如果有人知道的话,这会很有趣(尽管经过仔细考虑,mpi可能有充分的理由将他的文件描述符放在stdout&stderr的位置,例如它的--output文件名)。
有了这些信息,我可以提出3个解决方案(前两个是快速修复,第三个更好):
1/在启动python解释器的C代码中,在创建sys.stderr之前设置缓冲标志
Py_UnbufferedStdioFlag = 1; // force line_buffering for _all_ I/O
Py_Initialize();
这使得Python的回溯在所有情况下都能回到屏幕;但可能会带来灾难性的I/O。。。因此只有在调试模式下才是可接受的解决方案。
2/在python(嵌入式)脚本中,在最开始添加以下内容:
import sys
#sys.stderr.line_buffering = True # would be nice, but readonly attribute !
sys.stderr = open("error.log", 'w', buffering=1 )
然后,脚本将跟踪转储到此文件error.log。
我还尝试在PyErr_Print()之后添加一个对fflush(stderr)或ffrush(NULL)的调用。。。但这并没有起作用(因为sys.stderr有自己的内部缓冲)。不过,这将是一个不错的解决方案。
3/经过进一步的挖掘,我发现中的完美功能
Python/pythonrun.c:57:static void flush_io(void);
事实上,它是在该文件中的每个PyErr_Print之后调用的。不幸的是,它是静态的(只存在于该文件中,在Python.h中没有引用它,至少在3.6.0中是这样)。我将该文件中的函数复制到myprogram中,结果它确实完成了任务。
- 为什么使用数组元素查找最大数字的程序不起作用?
- 用于拆分空格字符串的程序不起作用
- 反转一个数字程序不起作用,为什么?
- C++从句子中删除给定字符的程序不起作用
- 为什么当我选择>250000个采样点时,程序不起作用?
- 我的C 程序不起作用
- C++加密程序不起作用
- 发送到64位应用程序不起作用
- 猪拉丁程序不起作用
- 结构程序不起作用
- 为什么程序不起作用
- 找不到WCHAR.H文件-Xcode 9.0中断QT创建者 - 旧修复程序不起作用
- C++为什么我的程序不起作用..:S.
- C++帮助!程序不起作用
- 如果我将类声明为常量,程序不起作用...而不是康特斯普?
- 为什么我的C++程序不起作用
- c++11-实现Promise的示例程序不起作用
- 为什么我的程序不起作用以及如何阻止它快速关闭
- 我的火狐扩展程序不起作用。使用C++XPCOM组件的Firefox扩展(XPI文件)的结构是什么?
- std::在C++中设置删除程序不起作用