寫在前面:python中的多線程其實並不是真正的多線程,如果想要充分地使用多核CPU的資源,在python中大部分情況需要使用多進程。Python提供了非常好用的多進程包multiprocessing,只需要定義一個函數,Python會完成其他所有事情。借助這個包,可以輕松完成從單進程到並發執行的轉換。
1.multiprocessing
模塊提供了一個Process
類來代表一個進程對象
import os import time import multiprocessing def run_proc(name): # 子進程要執行的代碼 print '運行子進程 %s ,子進程號為(%s)...' % (name, os.getpid()) print "我的處理內容是:%s+%s=?" % (name,name) return name if __name__=='__main__': start = time.time() print '父進程號為 %s.' % os.getpid() print('----------------------------------------') job = [] for i in range(3): p = multiprocessing.Process(target=run_proc, args=(i,))#多進程 job.append(p) print '子進程%d開啟...'%i p.start() # print '子進程%d結束...' %i print
#加join()可以讓主線程一直等待全部的子線程結束之后,主線程自身才結束,程序退出 for t in job: t.join()#join()方法可以等待子進程結束后再繼續往下運行,通常用於進程間的同步 end = time.time() print end-start
運行結果如下:
父進程號為 4924.
----------------------------------------
子進程0開啟...
子進程0結束...
子進程1開啟...
子進程1結束...
子進程2開啟...
運行子進程 0 ,子進程號為(5516)...
我的處理內容是:0+0=?
運行子進程 1 ,子進程號為(5517)...
我的處理內容是:1+1=?
運行子進程 2 ,子進程號為(5523)...
我的處理內容是:2+2=?
子進程2結束...
0.0220789909363
如果想要返回多進程process處理得到的結果,只需要利用multiprocessing 中的Manager類即可,稍改代碼:
import os import time from multiprocessing import Manager def run_proc(name,return_list): # 子進程要執行的代碼 print '運行子進程 %s ,子進程號為(%s)...' % (name, os.getpid()) print "我的處理內容是:%s+%s=?" % (name,name) return_list.append(name) if __name__=='__main__': print '父進程號為 %s.' % os.getpid() print('----------------------------------------') manager = Manager() return_list = manager.list() #return_dict = manager.dict() 也可以使用字典dict job = [] for i in range(3): p = multiprocessing.Process(target=run_proc, args=(i,return_list))#多進程 job.append(p) print '子進程%d開啟...'%i p.start() print '子進程%d結束...' %i print for t in job: t.join() print "所有子進程處理得到的結果都在return_list中,值為:",return_list
運行結果如下:
父進程號為 4924.
----------------------------------------
子進程0開啟...
子進程0結束...
子進程1開啟...
子進程1結束...
子進程2開啟...
運行子進程 0 ,子進程號為(5614)...
我的處理內容是:0+0=?
運行子進程 1 ,子進程號為(5616)...
我的處理內容是:1+1=?
運行子進程 2 ,子進程號為(5623)...
我的處理內容是:2+2=?
子進程2結束...
所有子進程處理得到的結果都在return_list中,值為: [0, 1, 2]
2.Pool:如果要啟動大量的子進程,可以用進程池的方式批量創建子進程:
from multiprocessing import Pool import os, time, random def long_time_task(name): print '運行任務 %s ,子進程號為(%s)...' % (name, os.getpid()) print "我就是子進程號為(%s)處理的內容" % (os.getpid()) start = time.time() time.sleep(random.random() * 3) end = time.time() print '任務 %s 運行了 %0.2f 秒.' % (name, (end - start)) return name if __name__=='__main__': print '父進程號為 %s.' % os.getpid() rst = [] p = Pool(4) #進程池中含有4個子進程 for i in range(5): #4個子進程完成5個任務,所以有一個任務是需要等某個進程空閑再處理 a = p.apply_async(long_time_task, args=(i,)) #a是進程處理函數long_time_task的返回結果 rst.append(a) #將次得到的結果添加到數組rst中去 print '等待所有子進程結束...' p.close() p.join()#等待所有子進程執行完畢。調用join()之前必須先調用close(),調用close()之后就不能繼續添加新的Process了。 print '所有子進程結束...'
運行結果如下:
父進程號為 3378. 運行任務 0 ,子進程號為(4621)... 運行任務 2 ,子進程號為(4624)... 運行任務 1 ,子進程號為(4622)... 我就是子進程號為(4621)處理的內容 我就是子進程號為(4622)處理的內容 運行任務 3 ,子進程號為(4627)... 我就是子進程號為(4624)處理的內容 我就是子進程號為(4627)處理的內容 任務 1 運行了 0.16 秒. 運行任務 4 ,子進程號為(4622)... 我就是子進程號為(4622)處理的內容 等待所有子進程結束... 任務 2 運行了 0.98 秒. 任務 4 運行了 0.89 秒. 任務 3 運行了 2.25 秒. 任務 0 運行了 2.89 秒. 所有子進程結束...
直接輸出rst不會得到想要的結果:
rst 運行結果: [<multiprocessing.pool.ApplyResult at 0x7ffa6c682c90>, <multiprocessing.pool.ApplyResult at 0x7ffa6c587590>, <multiprocessing.pool.ApplyResult at 0x7ffa6c587610>, <multiprocessing.pool.ApplyResult at 0x7ffa6c5876d0>, <multiprocessing.pool.ApplyResult at 0x7ffa6c587790>]
這是需要用到.get()方法:
rst = [i.get() for i in rst] rst 運行結果: [0, 1, 2, 3, 4]