我結束了同樣的問題(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