2015-03-30 69 views
0

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

当我在没有MPI启动程序的1个进程上执行程序(简单地调用./myprogram)时,该脚本正确执行并且其“打印”语句输出到终端。当脚本出现错误时,我使用PyErr_Print()在C++端打印它。

但是,当我通过mpirun(甚至在一个进程中)执行程序时,我没有从python代码中的“print”中得到任何输出。当我的脚本有错误时,我也没有从PyErr_Print()中得到任何东西。

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

关于如何解决这个问题的任何想法?

+0

Python应该使用stderr来打印出错误。 – 2015-03-30 17:35:07

+0

是的,但问题也出现在“打印”,我想,它使用标准输出... – sunmat 2015-03-30 17:37:23

回答

2

我结束了同样的问题(PyErr_Print不工作从一个mpirun)。追溯(涉及python3的一些GDB)和比较工作事物(./myprogram)和非工作事物(mpirun -np 1 ./myprogram),我结束于_io_TextIOWrapper_write_impl./Modules/_io/textio.c:1277(python-3.6.0顺便说一下)。

2次运行之间唯一的区别是self->line_buffering是1对0(此时self代表sys.stderr)。 然后,在pylifecycle.c:1128,我们可以看到谁决定这个值:

if (isatty || Py_UnbufferedStdioFlag) 
    line_buffering = Py_True; 

如此看来,MPI做了启动程序,这使得它不是一个TTY之前标准错误。我还没有调查是否有mpirun中的选项来保持stderr上的tty标志...如果有人知道,这将是有趣的(尽管第二个想法mpi可能有很好的理由把他的文件描述符代替标准输出&例如stderr,--output-filename)。在启动Python解释器的C代码

1 /,创造sys.stderr之前设置缓冲标志:

有了这个信息,我可以拿出2个快速解决方案。代码变为:

Py_UnbufferedStdioFlag = 1; // force line_buffering for _all_ I/O 
Py_Initialize(); 

这将Python的回溯带回所有情况下的屏幕;但可能会给灾难性的I/O ...所以只有在调试模式下可接受的解决方案。

2蟒(嵌入式)脚本/,在开始的时候补充一点:

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)的调用...但这不起作用(不知道为什么)。这将是最好的解决方案。


经过多一点挖掘,我发现在Python/pythonrun.c:57:static void flush_io(void);完美的功能。它实际上在这个文件中的每个PyErr_Print之后被调用。 不幸的是它是静态的(只存在于该文件中,没有在Python.h中引用它,至少在3.6.0中)。我把这个文件中的函数复制到myprogram中,结果完成了这个工作。

至于没有工作的fflush(stderr),那是因为sys.stderr有它自己的内部缓冲区。