一、摘要
python和java、C++不一樣,java一般在進行多項耗時計算時常采用多線程,而python則更适合采用多程序。關于線程和程序的差別,這裡不作詳細解釋。這裡介紹一種python開啟多程序的方法,使用multiprocessing.Pool程序池。
二、示例
import traceback
from multiprocessing import Pool
import time
def work(province, arr):
#在這裡進行複雜或耗時的計算
time.sleep(10)
print(arr)
print(time.strftime("%Y-%m-%d %H:%M:%S"), "finish....", province)
arr.append("新資料:" + province)
return arr
def workMulti(province, arr):
try:
work(province, arr)
except Exception as e:
print('Error: %s' % (province), traceback.print_exc())
if __name__ == '__main__':
provinces = ["北京市", "天津市", "上海市", "重慶市", "河北省",
"河南省", "雲南省", "遼甯省", "黑龍江省", "湖南省",
"廣西壯族自治區", "廣東省", "海南省"]
arr=["原資料"]
po = Pool(processes=5) #允許開幾個程序
for province in provinces:
print("Add task:", province)
# 開啟程序運作workMulti函數,傳入參數province,arr。
# 注意最後一個逗号是必須的,不是多餘的
po.apply_async(workMulti, args=(province,arr,))
print("AAA****************************")
po.close() #關閉程序池入口,此後不能再向程序池中添加任務了
print("BBB****************************")
po.join() #阻塞等待,隻有程序池中所有任務都完成了才往下執行
print("CCC****************************")
這裡開啟多程序去簡單列印省份,實際應用中隻需把複雜或耗時的計算放到work中即可。運作結果如下:
三、注意事項及建議
1、關于程序的開啟代碼一定要放在if __name__ == '__main__':代碼之下,不能放到函數中或其他地方。
2、po.apply_async(workMulti, args=(province,arr,))開啟程序調用workMulti,需要幾個參數傳幾個,最後需要加一個逗号,因為其傳遞的參數是tuple類型。
3、程序之間的參數變量是不共享的, 在某個程序中修改其函數參數, 在其他程序中是不可見的。這裡每次列印的都是['原資料']足以說明。
4、程序池接受任務并非阻塞式。這裡程序池雖然隻開5個,但它可以一次性接受很多任務, 任務的執行由程序池Pool自行安排,這裡列印的Add task是連續的,并不需要等待程序池有空程序。
5、這裡為何要調用workMulti而不直接調用work?
答:假如work函數中報錯,你會發現程式看起來運作正常,你将發現不了錯誤。通過在workMulti中加入try:...except:...以及traceback.print_exc(),我們可以列印出程序運作的異常。
6、多程序如何接收計算結果?
答:方法1:使用callback回調方法,我沒使用過,不詳細說明
方法2:在程序中把計算結果儲存下來,如儲存到資料庫或檔案,所有程序計算結束後再提取。我多采用這種方法,這種方法在部分程序計算失敗後仍然能保留計算成功的那些結果。
7、開啟多少個程序合适?
答:看你跑的是什麼類型的任務。如果是計算密集型(耗CPU的),建議開啟和CPU核心線程數一樣的程序,如果同時你還要操作計算機或進行其他任務,那最好再留出一點CPU,不然将會卡死。如果是耗時型(不耗CPU,如網絡請求等),可以考慮開多一些程序,不需要考慮CPU核心線程數。