寫在前面:html
在使用這些共享API的時候,咱們要注意如下幾點:安全
在UNIX平臺上,當某個進程終結以後,該進程須要被其父進程調用wait,不然進程成爲殭屍進程(Zombie)。因此,有必要對每一個Process對象調用join()方法 (實際上等同於wait)。對於多線程來講,因爲只有一個進程,因此不存在此必要性。多線程
multiprocessing提供了threading包中沒有的IPC(好比Pipe和Queue),效率上更高。應優先考慮Pipe和Queue,避免使用Lock/Event/Semaphore/Condition等同步方式 (由於它們佔據的不是用戶進程的資源)。app
多進程應該避免共享資源。在多線程中,咱們能夠比較容易地共享資源,好比使用全局變量或者傳遞參數。在多進程狀況下,因爲每一個進程有本身獨立的內存空間,以上方法並不合適。此時咱們能夠經過共享內存和Manager的方法來共享資源。但這樣作提升了程序的複雜度,並由於同步的須要而下降了程序的效率。dom
Process.PID中保存有PID,若是進程尚未start(),則PID爲None。函數
window系統下,須要注意的是要想啓動一個子進程,必須加上那句if __name__ == "main",進程相關的要寫在這句下面。spa
條件同步和條件變量同步差很少意思,只是少了鎖功能,由於條件同步設計於不訪問共享資源的條件環境。操作系統
圍繞一個標誌位來進行判斷線程
event=threading.Event():條件環境對象,初始值 爲False;設計
event.isSet():返回event的狀態值;
event.wait():若是 event.isSet()==False將阻塞線程;
event.set(): 設置event的狀態值爲True,全部阻塞池的線程激活進入就緒狀態, 等待操做系統調度;
event.clear():恢復event的狀態值爲False。
案例一:
import threading,time class Boss(threading.Thread): def run(self): print("BOSS:今晚你們都要加班到22:00。") event.isSet() or event.set() time.sleep(5) print("BOSS:<22:00>能夠下班了。") event.isSet() or event.set() class Worker(threading.Thread): def run(self): event.wait() print("Worker:哎……命苦啊!") time.sleep(0.25) event.clear() event.wait() print("Worker:OhYeah!") if __name__=="__main__": event=threading.Event() threads=[] for i in range(5): threads.append(Worker()) threads.append(Boss()) for t in threads: t.start() for t in threads: t.join()
案例二:
import threading,time import random def light(): if not event.isSet(): event.set() #wait就不阻塞 #綠燈狀態 count = 0 while True: if count < 10: print('\033[42;1m--green light on---\033[0m') elif count <13: print('\033[43;1m--yellow light on---\033[0m') elif count <20: if event.isSet(): event.clear() print('\033[41;1m--red light on---\033[0m') else: count = 0 event.set() #打開綠燈 time.sleep(1) count +=1 def car(n): while 1: time.sleep(random.randrange(10)) if event.isSet(): #綠燈 print("car [%s] is running.." % n) else: print("car [%s] is waiting for the red light.." %n) if __name__ == '__main__': event = threading.Event() Light = threading.Thread(target=light) Light.start() for i in range(3): t = threading.Thread(target=car,args=(i,)) t.start()
隊列由於是可使2遍都開口,因此FIFO,棧是開頭封閉,只能從底部出,因此先進後出
Python Queue模塊有三種隊列及構造函數:
一、Python Queue模塊的FIFO隊列先進先出。 class queue.Queue(maxsize)
二、LIFO相似於堆,即先進後出。 class queue.LifoQueue(maxsize)
三、還有一種是優先級隊列級別越低越先出來。 class queue.PriorityQueue(maxsize)
注意:列表時線程不安全的,隊列是安全的,內部有一把鎖保證了我數據的安全
import queue # 隊列長度可爲無限或者有限,默認是Queue(0),表示無限長 d = queue.Queue(2) #可經過Queue的構造函數的可選參數maxsize來設定隊列長度,若是maxsize小於1就表示隊列長度無限。 d.put('hello', 0) # 第一個item爲必需的,爲插入項目的值; # 第二個block爲可選參數,默認爲1。若是隊列當前爲空且block爲1,線程阻塞,直到空出一個數據單元 # 若是block爲0,put方法將引起Full異常。 d.put('world', 0) # d.put('2017', 0) # 第三個,阻塞報異常 print(d.get()) # get()方法從隊頭刪除並返回一個項目。可選參數爲block,默認爲True。 # 若是隊列爲空且block爲True,get()就使調用線程暫停,直至有項目可用。 # 若是隊列爲空且block爲False,隊列將引起Empty異常。 print(d.get())
隊列的方法
此包中的經常使用方法(q = Queue.Queue()): q.qsize() 返回隊列的大小 q.empty() 若是隊列爲空,返回True,反之False q.full() 若是隊列滿了,返回True,反之False q.full 與 maxsize 大小對應 q.get([block[, timeout]]) 獲取隊列,timeout等待時間 q.get_nowait() 至關q.get(False)非阻塞 q.put(item) 寫入隊列,timeout等待時間 q.put_nowait(item) 至關q.put(item, False) q.task_done() 在完成一項工做以後, q.task_done() 函數向任務已經完成的隊列發送一個信號
實例一:
import threading,queue from time import sleep from random import randint class Production(threading.Thread): def run(self): while True: r=randint(0,100) q.put(r) print("生產出來%s號包子"%r) sleep(1) class Proces(threading.Thread): def run(self): while True: re=q.get() print("吃掉%s號包子"%re) if __name__=="__main__": q=queue.Queue(10) threads=[Production(),Production(),Production(),Proces()] for t in threads: t.start()