我结束了同样的问题(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有它自己的内部缓冲区。
Python应该使用stderr来打印出错误。 – 2015-03-30 17:35:07
是的,但问题也出现在“打印”,我想,它使用标准输出... – sunmat 2015-03-30 17:37:23