Python“;“打印”;嵌入MPI程序时不工作 我有一个嵌入到C++ MPI应用程序中的Python 3解释器。此应用程序加载脚本并将其传递给解释器

Python“;“打印”;嵌入MPI程序时不工作 我有一个嵌入到C++ MPI应用程序中的Python 3解释器。此应用程序加载脚本并将其传递给解释器,python,c++,mpi,Python,C++,Mpi,当我在没有MPI启动器的情况下在1个进程上执行程序时(只需调用./myprogram),脚本将正确执行,其“print”语句将输出到终端。当脚本有一个错误时,我用PyrRyPrror().< /P>在C++侧打印它。 但是,当我通过mpirun启动程序时(即使是在单个进程上),我不会从python代码中的“print”中获得任何输出。当我的脚本出现错误时,我也不会从PyErr_Print()获得任何信息 我猜Python处理标准输出的方式与MPI(这里实际是Mpich)处理将进程的输出重定向到启

当我在没有MPI启动器的情况下在1个进程上执行程序时(只需调用./myprogram),脚本将正确执行,其“print”语句将输出到终端。当脚本有一个错误时,我用PyrRyPrror().< /P>在C++侧打印它。 但是,当我通过mpirun启动程序时(即使是在单个进程上),我不会从python代码中的“print”中获得任何输出。当我的脚本出现错误时,我也不会从PyErr_Print()获得任何信息

我猜Python处理标准输出的方式与MPI(这里实际是Mpich)处理将进程的输出重定向到启动器并最终重定向到终端的方式不匹配


有没有办法解决这个问题?

我也遇到了同样的问题(
PyErr\u Print
无法从MPI运行中运行)。追溯(涉及到python3的一些gdb)并比较工作事物(./myprogram)和非工作事物(mpirun-np1./myprogram),我最终在
\u io\u TextIOWrapper\u write\u impl
中找到了
/Modules/\u io/textio.c:1277
(顺便说一下,python-3.6.0)

这两次运行之间的唯一区别是
self->line\u 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 filename)

有了这些信息,我可以想出3个解决方案(前2个是快速修复,第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)或fflush(NULL)的调用。。。但这不起作用(因为sys.stderr有自己的内部缓冲)。这是一个很好的解决方案

3/经过进一步挖掘,我发现了

Python/pythonrun.c:57:static void flush_io(void);
实际上,它是在该文件中每次PyErr_打印后调用的。
不幸的是,它是静态的(只存在于该文件中,在Python.h中没有对它的引用,至少在3.6.0中是这样)。我把这个函数从这个文件复制到我的程序中,结果它正好完成了这个任务

Python应该使用stderr来打印错误。是的,但是“print”也会出现问题,我想,它使用stdout。。。