2015-03-30 65 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有它自己的內部緩衝區。