Python 2.6新增的multiprocessing,即多進程,給子進程代碼調試有點困難,比如python自帶的pdb如果直接在子進程代碼里面啟動會拋出一堆異常,原因是子進程的stdin/out/err等文件都已關閉,pdb無法調用。據聞winpdb、Wing IDE的調試器能夠支持這樣的遠程調試,但似乎過於重量級(好吧前者比后者要輕多了,但一樣要wxPython的環境,再說pdb的靈活可靠它們難以比擬)。
其實只需稍作改動即可用pdb繼續調試子進程的代碼,思路來自這個博客:子進程的stdin/out/err關閉了,那可以自己重新按/dev/stdout的名稱打開來用。當然這指*nix下,win下要麻煩一些,后面再說。
pdb支持自定義輸出輸入的文件,我再稍作改動,使用fifo管道(Named Pipe)來完成pdb的輸出輸入的重定向,這樣的好處是,可以同時對父子進程調試!
multiproces_debug.py
#!/usr/bin/python
import multiprocessing
import pdb
def child_process():
print "Child-Process"
pdb.Pdb(stdin=open('p_in', 'r+'), stdout=open('p_out', 'w+')).set_trace()
var = "debug me!"
def main_process():
print "Parent-Process"
p = multiprocessing.Process(target = child_process)
p.start()
pdb.set_trace()
var = "debug me!"
p.join()
if __name__ == "__main__":
main_process()
只需要給pdb的構造參數傳入stdin/stdout的文件對象,調試過程的輸出輸入就自然以傳入的文件為方向了。這里需要兩個管道文件p_in、p_out,運行腳本之前,使用命令mkfifo p_in p_out同時建立。這還未完成,還需要個外部程序來跟管道交互:
debug_cmd.sh
#!/bin/bash
cat p_out &
while [[ 1 ]]; do
read -e cmd
echo $cmd>p_in
done
很簡單的bash。因為fifo管道在寫入端未傳入數據時,讀取端是阻塞的(反之亦然),所以cat的顯示掛在后台,當調試的程序結束后,管道傳出EOF,cat就自動退出了。
實驗開始:先在一個終端運行debug_cmd.sh(其實順序無關),其光標停在新的一行,再在另外一個終端運行multiproces_debug.py,可見到兩個終端同時出現了(Pdb)的指示符,可以同時對父子進程調試了!

在Windows下使用管道就沒這么方便了,因為沒有實體的管道文件支持,可以考慮使用socket的類文件對象傳給pdb。但這樣要寫的python代碼就多一點,以及要另外用做個交互程序;不過依然用不了多少代碼,可以寫成一個模塊專門用做遠程調試,import即用。暫未實現,以后有空弄好放代碼出來。
Update: 專用調試模塊見《PDB遠程調試Python多進程子程序》
