互斥锁、共享内存方式以及生产者消费者模型
守護進程
1、守護進程的概念
進程指的是一個正在運行的程序,守護進程也是一個普通進程
意思就是一個進程可以守護另一個進程
import time from multiprocessing import Processdef task():print("子進程 走起!!!")time.sleep(5)print("子進程 掛掉了")if __name__ == '__main__':print("主進程 走起!!!")p = Process(target=task)p.daemon = True # 將子進程設置為守護進程 p.start()time.sleep(3)print("主進程 掛掉了") # --1)如果設置為守護進程,那么主進程一旦結束,那么子進程立馬也結束(代碼終止執行) # --2)如果沒有設置為守護進程,那么主進程結束執行完代碼之后,子進程還會繼續執行子進程里面的代碼2、結論
如果a 是 b 的守護進程,那么 b 就是被守護的進程, b要是(代碼運行完畢)死? ,a也會跟著死
守護進程在主進程代碼運行結束之后就死了
3、使用場景
父進程交給了子進程一個任務,任務還沒有完成父進程就結束了,子進程就沒有繼續執行的意義了
例如qq接到一個視頻文件,于是開啟了一個子進程來下載,如果中途退出了qq,下載任務就沒必要繼續執行了
互斥鎖(重點)
為什么需要互斥鎖
當我們同時開啟幾個子進程的時候,而這幾個子進程又要同時操作一個資源(文件或者控制臺),
將會導致數據的錯亂問題(誰先搶到誰打印,數據混亂看不懂)
解決方案1:
加join? ? (就是每開一個子進程,就加一個join,限制后面的子進程不能開啟)
弊端:
--1、把原本并發的任務變成了串行,避免了數據錯亂問題,但是效率降低了,
而且是執行完第一個子進程才開啟第二個子進程,都放在主程序也是同樣效果,沒必要開子進程
--2、原本多個進程之間公平競爭,join執行的順序是定死的,不合理
解決法案2:
給公共資源加鎖(互斥鎖)
互斥鎖,字面理解就是互相排斥的鎖,在程序中指的是,如果這個資源已經被鎖住了,其他進程就無法使用
需要強調的是:鎖,并不是真正的把資源鎖起來,只是在代碼里加限制,限制你的代碼不能執行
import time,random from multiprocessing import Process,Lockdef task1(lock):lock.acquire() # 上鎖print('任務一 走起')time.sleep(random.randint(0,2))print('任務一 結束')lock.release() # 解鎖def task2(lock):lock.acquire()print('任務二 走起')time.sleep(random.randint(0,2))print('任務二 結束')lock.release()def task3(lock):lock.acquire()print('任務三 走起')time.sleep(random.randint(0,2))print('任務三 結束')lock.release()if __name__ == '__main__':lock = Lock()p1 = Process(target=task1,args=(lock,))p2 = Process(target=task2,args=(lock,))p3 = Process(target=task3,args=(lock,))p1.start()p2.start()p3.start()注意:
--1、不要對同一代碼執行多次acquire,會鎖死程序無法執行,一次acquire必須對應一次release
? (一次加鎖相當于在代碼做一次判斷,判斷成功改狀態,再加鎖又相當于做一次判斷,判斷就會失敗,鎖死)
--2、想要保證數據安全,必須保證所有進程使用同一把鎖
(如果每個進程拿到的鎖都不一樣,那么判斷的條件就不會同步)
鎖和join的區別
1、join是固定了執行順序,會造成父進程等待子進程
鎖依然是公平競爭,誰先搶到誰先執行,父進程也可以執行其他任務
2、最主要的區別:
join是把進程的所有任務全部串行
鎖可以所以任意代碼,一行也可以,可以自己調整粒度? 粒度(指的是被鎖住代碼的大小,越小效率越快)
IPC
IPC就是進程間通訊,通訊指的是交換數據
進程之間的內存是相互隔離的,當一個進程想要把數據給另外一個進程,就需要考慮到IPC
IPC方式:
管道:只能單向通訊(一邊讀,一邊寫),數據都是二進制
文件:在硬盤上創建共享文件
優點:硬盤的空間大,所以共享的數據量幾乎沒有限制
缺點:硬盤讀取速度慢
socket:編程復雜度高
共享內存: 必須由操作系統來分配? ? ?(必須掌握)
優點:速度快
缺點:數據量不能太大
共享內存的方式
1、Manager類
Manager提供了很多數據結構,如list,dict等等(可以在源碼中看到)
Manager所創建出來的數據結構,具備進程間共享的特點
from multiprocessing import Manager,Process,Lock import timedef task(dic,lock):lock.acquire() # 這里如果不加鎖的話,可能出現多個進程剛取出來的值都是100,然后修改完都是99nums = dic["nums"]# time.sleep(2) # 所有進程拿到100睡2秒,最后修改的數據就是99dic["nums"] = nums - 1lock.release() if __name__ == '__main__':lock = Lock()m = Manager() # 創建一個manager對象dic = m.dict({"nums":100}) # 括號里需要的是一個映射關系,幫我們生成一個進程間共享的字典for i in range(5):p = Process(target=task,args=(dic,lock))p.start()time.sleep(10)print(dic["nums"])需要注意的是:manager創建的一些數據結構是不帶鎖的,可能會出現同時修改一個數據的情況,會出問題,不推薦使用、
2、Queue隊列 幫我們處理了鎖的問題 (重點)
隊列是一種特殊的數據結構,先存儲的先取出,就像排隊,先進的先出
相反的就是堆棧,先存取的后取出,就像把衣服疊進箱子,取的時候先取后疊進去的
函數嵌套調用時,執行的順序也是先進后出,也稱之為函數棧
from multiprocessing import Queueq = Queue(maxsize=3) # 創建一個隊列,里面的參數表示的是隊列的容量,如果不寫默認無限大# 存數據 q.put() 放進去 q.put("a") q.put("b") q.put("c") # q.put("d") # 如果隊列里面已經滿了,你還繼續往里放,他就會進入阻塞狀態,一直等到隊列有空位置把數據放進去# 取數據 q.get() 拿出來 print(q.get()) print(q.get()) print(q.get()) # print(q.get()) # 同樣的,如果隊列里面已經空了,你還繼續取,它也會進入阻塞狀態,一直等到隊列里有數據然后取出來 q.get(block=True,timeout=2) # 里面block參數表示的是是否阻塞,默認True(阻塞),當設置為False時,并且隊列為空時會立馬拋出異常 q.put("aaa",block=True,timeout=2) # 里面block參數表示的是是否阻塞,默認True(阻塞),當設置為False時,并且隊列為滿時會立馬拋出異常 # timeout 表示的時阻塞的超時時間,超過時間還是沒有位置或著空的話就會拋出異常生產者消費者模型 (重點)
1、概念
模型? 就是解決某個問題的套路
產生數據的一方稱之為生產者
處理數據的一方稱之為消費者
例如:飯店廚師就是生產者,吃飯的人就是消費者
2、生產者和消費者產生的問題
生產者和消費者,處理速度不平衡,一方快一方慢,導致一方需要等待另一方再能接著往下執行
3、生產者消費者模型解決這個問題的思路
原本,雙方是耦合在一起,消費者必須等待生產著生成完畢再開始處理,反過來,
如果消費者消費速度太慢,生產著必須等待其處理完畢才能開始生成下一個數據
4、解決的方案
將雙方分開來,一方專門,負責生產,一方專門負責處理
一樣一來,雙方的數據就不能直接交互了,雙方需要共同的容器
這樣就解決了雙方能力不平衡的問題,做的快的一方可以繼續做,不需要等待另一方,提高了整體的運行效率
from multiprocessing import Process,Queue import time,random def eater(q):for i in range(5):time.sleep(random.randint(0, 2))food = q.get()print("%s吃完了"%food)def cooker(q):for i in ["包子","骨頭","土","面","刀子"]:time.sleep(random.randint(0, 2))q.put(i)print("%s做好了"%i)if __name__ == '__main__':q = Queue()cp = Process(target=cooker,args=(q,))ep = Process(target=eater,args=(q,))cp.start()ep.start()轉載于:https://www.cnblogs.com/hesujian/p/10968848.html
總結
以上是生活随笔為你收集整理的互斥锁、共享内存方式以及生产者消费者模型的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 推荐一款好用的redis客户端工具
- 下一篇: Time profile 使用