標籤:nat col reading char 進程間 分享 manager 不能 ase
什麼是進程?
程式不能單獨執行,只有將程式裝載到記憶體中,系統為它分配資源才能運行,而這種執行的過程就叫做進程。進程是作業系統調度的最小單位。
程式和進程的區別在於:程式是儲存在硬碟上指令的有序集合,是靜態;進程是程式的一次執行過程,屬於動態概念。
線程和進程的區別:
進程是資源的集合,進程要在CPU執行,必須要建立線程,至少要有一個線程在運行。
1.線程共用建立它的進程的地址空間。進程的記憶體空間是獨立的。
2.線程可以直接存取其進程的資料區段(不同線程共用同一個進程的資料),進程間不共用。
3.線程可以與其他線程進行通訊,進程必須使用處理序間通訊(中間代理)與同級進程進行通訊。
4.新的線程很容易建立,新的進程需要父進複製。
5.線程可以直接操作和控制同一進程內的其它線程,而進程只能操作子進程。
6.對主線程的修改可能會影響到其它線程的行為。對父進程的修改不會影響子進程(不刪除父進程的前提下)。
Python多進程的使用
Process 類用來描述一個進程對象。建立子進程的時候,只需要傳入一個執行函數和函數的參數即可完成 Process 樣本的建立。
star() 方法啟動進程。
join() 方法實現進程間的同步,等待所有進程退出。
close() 用來阻止多餘的進程湧入進程池 Pool 造成進程阻塞。
multiprocessing.Process(group=None, target=None, name=None, args=(), kwargs={}, *, daemon=None)
target 是函數名字,需要調用的函數
args 函數需要的參數,以 元組 的形式傳入
multiprocessing模組的使用跟線程類似
import multiprocessingimport threadingimport timedef t_run(): print("線程號",threading.get_ident()) # 線程iddef run(name): time.sleep(1) print(‘hello‘, name) t = threading.Thread(target=t_run) t.start()if __name__ == ‘__main__‘: for i in range(10): p = multiprocessing.Process(target=run, args=(i,)) p.start()multiprocessing
所有的進程都是由父進程啟動的,所以發現此程式的父進程ID正是PyCharm。
每個進程都是相互獨立的,存在於不同的記憶體位址。
處理序間通訊
- 首先聲明一點,這裡所說的處理序間通訊指的是父子進程之間的通訊機制。如果兩個進程間沒有關係,這裡的機制是無法奏效的。
- 通訊方式有:進程隊列Queue、管道通訊Pipe、共用資料Manger
1.進程隊列Queue
進程隊列直接使用multiprocessing模組的Queue類,不同於線程隊列的queue模組。
import multiprocessingdef f(q): q.put([42, None, ‘hello‘]) q.put(30)if __name__ == ‘__main__‘: q = multiprocessing.Queue() p = multiprocessing.Process(target=f, args=(q,)) # 將隊列copy一份傳給子進程 p.start() print(q.get()) # 在父進程中取出隊列中資料 print(type(q.get())) p.join()
進程隊列2.管道Pipe
兩個進程在管道兩邊收發資料。
import multiprocessing‘‘‘Pipe管道執行個體,兩個進程在管道兩邊收發資料‘‘‘def f(conn): conn.send([42, None, ‘hello‘]) # 發送資料 print("child_conn接收:",conn.recv()) # 接收資料 conn.close()def s(conn): conn.send("你好,紫禁城") # 發送資料 print("parent_conn接收:",conn.recv()) # 接收資料 conn.close()if __name__ == ‘__main__‘: parent_conn, child_conn = multiprocessing.Pipe() # 管道執行個體,串連著兩個進程 p = multiprocessing.Process(target=f, args=(child_conn,)) p2 = multiprocessing.Process(target=s,args=(parent_conn,)) p.start() p2.start() #print(parent_conn.recv()) # 父進程接收管線的資料 #parent_conn.send("你好,紫禁城") # 父進程發送資料 p.join() p2.join()Pipe3.進程間共用資料Manger
使用Manger()可以建立共用的資料,包括列表,字典,元組等多種類型。
from multiprocessing import Process, Manager def f(d, l): d[1] = ‘1‘ d[‘2‘] = 2 d[0.25] = None l.append(1) print(l) if __name__ == ‘__main__‘: with Manager() as manager: d = manager.dict() l = manager.list(range(5)) p_list = [] for i in range(10): p = Process(target=f, args=(d, l)) p.start() p_list.append(p) for res in p_list: res.join() print(d) print(l)
MangerLock
螢幕鎖,防止一個進程未列印完畢,另一個進程插入
def f(l,i): l.acquire() print("hello",i) l.release()if __name__ == ‘__main__‘: l=Lock() for i in range(10): Process(target=f,args=(l,i)).start()lock進程池
在利用Python進行系統管理的時候,特別是同時操作多個檔案目錄,或者遠端控制多台主機,並行操作可以節約大量的時間。當被操作對象數目不大時,可以直接利用multiprocessing中的Process動態成生多個進程,10幾個還好,但如果是上百個,上千個目標,手動的去限制進程數量卻又太過繁瑣,這時候進程池Pool發揮作用的時候就到了。
Pool可以提供指定數量的進程,供使用者調用,當有新的請求提交到pool中時,如果池還沒有滿,那麼就會建立一個新的進程用來執行該請求;但如果池中的進程數已經達到規定最大值,那麼該請求就會等待,直到池中有進程結束,才會建立新的進程來它。這裡有一個簡單的例子:
from multiprocessing import Process, Poolimport time, os def Foo(i): time.sleep(5) print(‘in process[Foo]‘, os.getpid()) return i + 100 def Bar(arg): # 父進程去執行,而不是子進程調用 print(‘-->exec done:‘, arg) print(‘in process[Bar]‘, os.getpid()) if __name__ == ‘__main__‘: pool = Pool(5) # 允許進程池裡同時放入5個進程 其他多餘的進程處於掛起狀態 for i in range(10): pool.apply_async(func=Foo, args=(i,), callback=Bar) # pool.apply(func=Foo, args=(i,)) print(‘end:‘, os.getpid()) pool.close() # close() 必須在join()前被調用 pool.join() # 進程池中進程執行完畢後再關閉,如果注釋,那麼程式直接關閉。
進程池
- pool.apply_async()用來向進程池提交目標請求。
- pool.join()是用來等待進程池中的worker進程執行完畢,防止主進程在worker進程結束前結束。但pool.join()必須使用在pool.close()或者pool.terminate()之後。
- close()跟terminate()的區別在於close()會等待池中的worker進程執行結束再關閉pool,而terminate()則是直接關閉。
- result.successful()表示整個調用執行的狀態,如果還有worker沒有執行完,則會拋出AssertionError異常。
- 利用multiprocessing下的Pool可以很方便的同時自動處理幾百或者上千個並行操作,指令碼的複雜性也大大降低.
初學Python——進程