多進程介紹
Python多線程無法利用CPU多核的優勢。因此在Python開發中,我們一般使用多進程進行並行開發。multiprocessing是類似於threading模塊的包。它支持了本地和遠程併發性,可以更充分的利用多核資源。
Process類
要運行一個進程需要創建實例化一個Process對象並且調用該類的start()方法。
`
from multiprocessing import Process
def greet(name):
print('hello', name)
if __name__ == '__main__':
p = Process(target=f, args=('bob',))
p.start()
p.join()`
Process([group [, target [, name [, args [, kwargs]]]]]),group默認爲None,不使用,參數target爲調用的對象,name爲子進程的名字,args爲調用對象的參數元組,kwargs爲調用對象的字典。
有關的方法和屬性
Process中的方法與threading.Thread中的十分相似。
run():進程啓動時運行的方法。
start():啓動進程,會調用子進程中的run()方法。
join([timeout]):主線程等待當前線程終止,timeout爲可選的超時時間,join只能join住start開啓的進程,而不能join住run開啓的進程。
terminate():強制終止進程,不會進行任何清理操作,如果創建了子進程,該子進程就成了殭屍進程。如果進程還保存了一個鎖那麼也將不會被釋放,進而導致死鎖。
is_alive():判斷進程是否在運行,爲bool值。
name:進程的名字,它是string類型,沒有語義,只是用於標誌進程,多進程中允許使用同一個名字。
dameon:必須在start()調用前設置,默認爲false,如果設爲True,代表當前進程爲後臺運行的守護進程,當前進程的父進程終止時,它也隨之終止,並且設定爲True後,不能創建自己的新進程。
pid:進程的id
每個進程還有特有的id號,可以通過os.getpid()得到當前進程的ID號,也可以直接使用p.pid得到ID。
from multiprocessing import Process
import os
def info(title):
print(title)
print('module name:', __name__)
print('parent process:', os.getppid())#得到父進程的id號
print('process id:', os.getpid())#得到當前進程的id號
def greet(name):
info('function greet')
print('hello', name)
if __name__ == '__main__':
info('main Process')
p = Process(target=greet, args=('bob',))
p.start()
p.join()
進程間的通信
多進程支持兩種進程間通信的方式:隊列和管道。
隊列
隊列具有先進先出的特點,並且它是線程和進程安全的,通過q.put()方法將數據插入到隊列中,然後使用q.get()方法將數據取出。
from multiprocessing import Process, Queue
def greet(q):
q.put("hello")
if __name__ == '__main__':
q = Queue()
p = Process(target=f, args=(q,))
p.start()
print(q.get()) # 打印hello
p.join()
管道
Pipe()函數返回一對雙向的連接對象,它們代表管道的兩端。每個連接對象有send()和recv()方法。當兩個進程或者線程試圖同時寫入或讀取管道的一端時,管道中的數據會被損壞,當然同一時刻使用不同的管道端口不會有損壞的風險。
from multiprocessing import Process, Pipe
def greet(p):
p.send("hello")
p.close()
if __name__=='__main__':
left_p,right_p=Pipe()
p=Process(target=greet,args=(right_p,))
p.start()
print(left_p.recv()) #輸出hello
p.join()
進程間的同步
多進程包含與多線程中等價的同步原語。例如可以使用鎖機制確保某一時刻只有一個進程打印到標準輸出。
from multiprocessing import Process, Lock
def greet(lock,num):
lock.acquire() #獲取鎖
print("hello",num)
lock.release() #將鎖釋放
if __name__=='__main__':
lock=Lock()
for num in range(5):
Process(target=greet,args=(lock,num),).start()
進程間分享狀態
在進行併發編程時,最好儘量避免使用共享狀態,尤其是使用多進程時。但是,如果你確實要使用一些共享的數據,多進程也提供一些方法。
共享內存
數組可以利用Value和Array存儲在共享內存映射中。
from multiprocessing import Process, Value, Array
def share(val,arr):
val.value=1
for i in range(len(arr)):
arr[i]=arr[i]+1
if __name__=='__main__':
val=Value('d',0.0)
arr=Array('i',range(10))
p=Process(target=share,args=(val,arr))
p.start()
p.join()
print(val.value)
print(arr[:])
輸出值爲:
`1.0
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
`
其中d和i分別代表創建Value和Array中存儲的數字類型爲double和signed integer。這些共享對象都是線程和進程安全的。
服務器進程
通過Manager()創建一個管理類,它可以控制一個服務器進程,這些服務器進程持有Python對象,並且允許其他進程利用代理來操縱Python對象。
from multiprocessing import Process, Manager
def func(dic,li):
dic['hello']=1
dic[1]='Bob'
dic[2.01]=None
li.reverse()
if __name__=='__main__':
manager=Manager()
dic=manager.dict()
li=manager.list(range(5))
p=Process(target=func,args=(dic,li))
p.start()
p.join()
print(dic)
print(li)
輸出結果爲:
{'hello': 1, 1: 'Bob', 2.01: None}
[4, 3, 2, 1, 0]
服務器進程管理比使用共享內存對象更加的靈活,因爲它可以支持任意類型的對象。manager也可以通過進程進行共享,只不過比使用共享內存慢。
進程池
進程池中有許多進程,它有方法讓進程池中的進程以不同的方式運行任務。 可以創建一個池池,這些進程將執行池類向它提交的任務。
多進程編程並不是進程越多越好,還與CPU核數有關,進程數過多反而會降低效率。
Pool([processes[, initializer[, initargs[, maxtasksperchild]]]])
相關方法
apply(func[, args[, kwds]]):在一個池工作進程中執行func(*args,**kwargs),然後返回結果。需要強調的是:此操作並不會在所有池工作進程中並執行func函數。如果要通過不同參數併發地執行func函數,必須從不同線程調用p.apply()函數或者使用
p.apply_async()
apply_async(func [, args [, kwargs]]):在一個池工作進程中執func(*args,**kwargs),然後返回結果。此方法的結果是AsyncResult類的實例,callback是可調用對象,接收輸入參數。當func的結果變爲可用時,將理解傳遞給callback。callback禁止執行任何阻塞操作,否則將接收其他異步操作中的結果。
close():關閉進程池。如果所有操作持續掛起,它們將在工作進程終止前完成。
P.join():等待所有工作進程退出。此方法只能在close()或teminate()之後調用
from multiprocessing import Pool
def sqr(x):
return x*x
if __name__=='__main__':
pool=Pool(processes=5) #開啓5個工作進程
result=pool.apply_async(sqr,[10]) #異步計算sqr(10))
print(result.get(timeout=1)) #輸出100
print(pool.map(sqr,range(5))) #輸出[0,1,4.....16]
參考
https://www.cnblogs.com/smallmars/p/7093603.html
http://docspy3zh.readthedocs.io/en/latest/library/multiprocessing.html