多進程
按書面語來解釋進程是計算機中的程序關於某數據集合上的一次運行活動,是系統進行資源分配和調度的基本單位,是操作系統結構的基礎。
多線程無法利用多核的優勢,python提供了mutiprocessing.
multiprocessing模塊用來開啓子進程,並在子進程中執行我們定製的任務(比如函數),multiprocessing模塊的功能衆多:支持子進程、通信和共享數據、執行不同形式的同步,提供了Process、Queue、Pipe、Lock等組件。
import os
print(os.cup_count()) # 查看cpu的核心數
linux下可以使用fork開啓新進程
import os
print('Process (%s) start...' % os.getpid())
pid = os.fork() #開啓新進程
if pid==0:
print('I am child process (%s) and my parent is %s.' % (os.getpid(), os.getppid()))
os._exit(1)
else:
print('I (%s) just created a child process (%s).' % (os.getpid(), pid))
一個fork()屬於系統調用,它比較特殊。調用一次,返回兩次,因爲操作系統自動把當前進程和子進程進行返回。子進程永遠返回0,而父進程返回子進程的ID。
multiprocessing模塊
創建一個進程時,只需要傳入一個執行函數和函數的參數,創建一個
Process實例,用start()方法啓動,這樣創建進程比fork()還要簡單。
join()方法可以等待子進程結束後再繼續往下運行,通常用於進程間的同
步。
process語法結構
Process([group [, target [, name [, args [, kwargs]]]]])
參數 | 作用 |
---|---|
target | 表示這個進程實例所調用的對象 |
args | 表示調用對象的位置參數元組 |
kwargs | 表示調用對象的關鍵字參數字典 |
name | 爲當前進程實例的別名 |
group | 在多數情況下用不到 |
process類常見函數
函數 | 功能 |
---|---|
is_alive() | 判斷進程實例是否還在執行 |
join([timeout]) | 是否等待進程實例執行結束,或等待多少秒 |
start() | 啓動進程實例(創建子進程) |
run() | 如果沒有給定target參數,對這個對象調用start()方法時,就將執行對象中的run()方法 |
terminate() | 不管任務是否完成,立即終止 |
編程練習
#coding=utf-8
from multiprocessing import Process
import os
from time import sleep
#子進程要執行的函數
def run_proc(name,age,**kwargs):
for i in range(10):
print('子進程執行中,name = %s, age = %d, pid = %d'%(name, age, os.getpid())
print(kwargs)
sleep(0.5)
if __name__ == "__main__":
print('父進程 %d'%os.getpid())
p = Process(target=run_proc,args=('xiaoming',18),kwargs={'xiaohua':19})
print('子進程將要執行')
#啓動子進程
p.start()
#等待一秒之後
sleep(1)
#立即結束
p.terminate() #立即關閉進程
#join()⽅法可以等待⼦進程結束後再繼續往下運⾏,通常⽤於進程間的同步。
p.join()
print('子進程已結束')結果:
進程運行完成後會自動退出
進程池
開多進程的目的是爲了併發,如果有多核,通常有幾個核就開幾個進程,進程開啓過多,效率反而會下降(開啓進程是需要佔用系統資源的,而且開啓多餘核數目的進程也無法做到並行),但很明顯需要併發執行的任務要遠大於核數,這時我們就可以通過維護一個進程池來控制進程數目,比如httpd的進程模式,規定最小進程數和最大進程數…
在利用Python進行系統管理的時候,特別是同時操作多個文件目錄,或者遠程控制多臺主機,並行操作可以節約大量的時間。當被操作對象數目不大時,可以直接利用multiprocessing中的Process動態成生多個進程,十幾個還好,但如果是上百個,上千個目標,手動的去限制進程數量卻又太過繁瑣,此時可以發揮進程池的功效。
Pool可以提供指定數量的進程供用戶調用,當有新的請求提交到pool中時,如果池還沒有滿,那麼就會創建一個新的進程用來執行該請求;但如果池中的進程數已經達到規定最大值,那麼該請求就會等待,直到池中有進程結束,纔會創建新的進程來它。
**Pool([numprocess [,initializer [, initargs]]]):創建進程池 **
參數 | 作用 |
---|---|
numprocess | 要創建的進程數,如果省略,將默認使用cpu_count()的值 |
initializer | 是每個工作進程啓動時要執行的可調用對象,默認爲None |
initargs | 是要傳給initializer的參數組 |
函數介紹
函數 | 作用 |
---|---|
apply_async(func[, args[, kwds[, callback]]]) | 它是非阻塞 |
apply(func[, args[, kwds]]) | 是阻塞的 |
close() | 關閉pool,使其不在接受新的任務 |
terminate() | 結束工作進程,不在處理未完成的任務 |
join() | 主進程阻塞,等待子進程的退出, join方法要在close或terminate之後使用 |
編程練習
import multiprocessing
import time
def func(msg):
print "msg:", msg
time.sleep(3)
print "end"
if __name__ == "__main__":
pool = multiprocessing.Pool(processes = 3)
for i in xrange(4):
msg = "hello %d" %(i)
pool.apply_async(func, (msg, )) #維持執行的進程總數爲processes,當一個進程執行完畢後會添加新的進程進去 這個是非阻塞的
print "Mark~ Mark~ Mark~~~~~~~~~~~~~~~~~~~~~~"
pool.close()
pool.join() #調用join之前,先調用close函數,否則會出錯。執行完close後不會有新的進程加入到pool,join函數等待所有子進程結束
print "Sub-process(es) done."
import multiprocessing
import time
def func(msg):
print "msg:", msg
time.sleep(3)
print "end"
return "done" + msg
if __name__ == "__main__":
pool = multiprocessing.Pool(processes=4)
result = []
for i in xrange(3):
msg = "hello %d" %(i)
result.append(pool.apply_async(func, (msg, )))
pool.close()
pool.join()
for res in result:
print ":::", res.get() #得出每個返回結果的值
print "Sub-process(es) done."