1. 程式人生 > >守護程序,互斥鎖,IPC,生產者與消費者模型

守護程序,互斥鎖,IPC,生產者與消費者模型

守護程序:
b 程序守護 a程序,當a程序執行完畢時,b程序會跟著立馬結束
守護程序用途:
如果父程序結束了,子程序無需運行了,就可以將子程序設定為父程序的守護程序
例如我們qq視訊聊天時,當我們退出qq時,視訊介面會跟著退出,視訊就是qq的守護程序
守護程序語法:
p.daemon = True

#1.未設定守護程序
from multiprocessing import Process
import time
def task():
    print("子程序run")
    time.sleep(2)
    print("子程序over")
if __name__ == '__main__':
    print("主程序run")
    p = Process(target = task)
    p.start() 
    print("主程序over")
#執行結果
# 主程序run
# 主程序over
# 子程序run
# 子程序over
#2.設定守護程序
from multiprocessing import Process
import time
def task():
    print("子程序run")
    time.sleep(2)
    print("子程序over")
if __name__ == '__main__':
    print("主程序run")
    p = Process(target = task)
    p.daemon = True
    p.start()
    time.sleep(0.5)#讓子程序起來
    print("主程序over")
#執行結果:
#主程序run
# 子程序run
# 主程序over

#3.坑
from multiprocessing import Process
import time
def foo():
    print(123)
    time.sleep(1)
    print("end123")

def bar():
    print(456)
    time.sleep(3)
    print("end456")

if __name__ == '__main__':

    p1=Process(target=foo)
    p2=Process(target=bar)

    p1.daemon=True
    p1.start()
    p2.start()
    print("main-------")
#列印完print  main主程序就算結束了,作為守護程序的p1就掛了不會執行,而p2會執行完畢,主程式終止
#主程式的執行完畢和終止是兩個概念,執行完畢是主程序的程式碼執行完,主程序終止 py檔案停止執行
#執行結果
#main-------
#3456
#end456

強調:
設定守護程序需在子程序物件啟動之前,即順序如下:
p.daemon = True
p.start()
否則報錯

Traceback (most recent call last):

# File "D:/作業/12.28/test.py", line 13, in

AssertionError: process has already started

互斥鎖:
多個程序共享一份資料時,可能會造成資料錯亂
此時我們需要加鎖處理

from multiprocessing import Process
import time
import random
def task1():
    print("name1:wxx")
    time.sleep(random.random())
    print("age1:20")
    time.sleep(random.random())
    print("sex1:sm")
def task2():
    print("name2:egon")
    time.sleep(random.random())
    print("age2:19")
    time.sleep(random.random())
    print("sex2:fm")
def task3():
    print("name3:zb")
    time.sleep(random.random())
    print("age3:18")
    time.sleep(random.random())
    print("sex3:m")
if __name__ == '__main__':
    p1 = Process(target=task1)
    p2 = Process(target=task2)
    p3 = Process(target=task3)
    p1.start()
    p2.start()
    p3.start()
#執行結果
name1:wxx
# name2:egon
# name3:zb
# age2:19
# sex2:fm
# age3:18
# age1:20
# sex3:m
# sex1:sm

#如上模擬三個列印任務共享一臺印表機,打印出的結果是亂的,不是我們想要的結果,此時cpu的利用率是高的

#解決辦法:
#1.join改併發為序列,保證了資料不會亂,但執行順序人為規定,喪失了公平性
from multiprocessing import Process
import time
import random
def task1():
    print("name1:wxx")
    time.sleep(random.random())
    print("age1:20")
    time.sleep(random.random())
    print("sex1:sm")
def task2():
    print("name2:egon")
    time.sleep(random.random())
    print("age2:19")
    time.sleep(random.random())
    print("sex2:fm")
def task3():
    print("name3:zb")
    time.sleep(random.random())
    print("age3:18")
    time.sleep(random.random())
    print("sex3:m")
if __name__ == '__main__':
    p1 = Process(target=task1)
    p2 = Process(target=task2)
    p3 = Process(target=task3)
    p1.start()
    p1.join()
    p2.start()
    p2.join()
    p3.start()
#執行結果
#name1:wxx
# age1:20
# sex1:sm
# name2:egon
# age2:19
# sex2:fm
# name3:zb
# age3:18
# sex3:m

#2加入互斥鎖:
from multiprocessing import Process,Lock
import time
import random
def task1(lock):
    lock.acquire()
    print("name1:wxx")
    time.sleep(random.random())
    print("age1:20")
    time.sleep(random.random())
    print("sex1:sm")
    lock.release()
def task2(lock):
    lock.acquire()
    print("name2:egon")
    time.sleep(random.random())
    print("age2:19")
    time.sleep(random.random())
    print("sex2:fm")
    lock.release()
def task3(lock):
    lock.acquire()
    print("name3:zb")
    time.sleep(random.random())
    print("age3:18")
    time.sleep(random.random())
    print("sex3:m")
    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.window系統,子程序的記憶體空間和父程序的記憶體空間完全獨立,互不影響,此時多個子程序應該搶同一個鎖,所以我們在if name == “main”中,新建一個鎖,然後把鎖傳給各個子程序,保證了子程序搶的是同一把鎖
2.搶到鎖後,執行完程式碼,一定要記得釋放鎖
3.使用lock時,只可require一次,不可連續require

RLock可重入鎖
首先是互斥鎖
鎖幾次要開幾次

死鎖:
死鎖的前提是有多把鎖
程式遇到鎖請求就會卡主,等釋放
正常開發時,一把鎖足夠使用,不要開多把鎖

IPC inter process communication 程序間通訊

1.共享資料

2.在記憶體裡

3.幫我們自動加鎖

1.通過檔案
可以傳輸大檔案,IO時間長,從硬碟讀資料慢
2.管道:基於記憶體,速度快,單向通訊,使用麻煩
3.佇列,申請共享記憶體空間
傳輸資料不能太大,速度快,
不只用於程序間通訊,也是一種常見的資料容器
特點是:先進先出
對比堆疊剛好相反:後進先出

佇列語法
```python
Queue
q = Queue(1)
q.put()放入任何型別都可以
當放滿時會阻塞,
q.put(data,block = True, timeout = None)
三個引數,資料,是否阻塞,超時時間
當放滿時,設定不阻塞時,會報錯
q.get()
q.get(block = True,timeout = None)
是否阻塞,超時時間
當取完時,設定不阻塞時,會報錯

生產者消費者模型:
1.生產者不停生產
2.消費者不停消費
3.生產者消費者之間以佇列進行資料溝通

生產者消費者模型
在併發程式設計中使用生產者和消費者模式能夠解決絕大多數併發問題。該模式通過平衡生產執行緒和消費執行緒的工作能力來提高程式的整體處理資料的速度。

為什麼要使用生產者和消費者模式
線上程世界裡,生產者就是生產資料的執行緒,消費者就是消費資料的執行緒。在多執行緒開發當中,如果生產者處理速度很快,而消費者處理速度很慢,那麼生產者就必須等待消費者處理完,才能繼續生產資料。同樣的道理,如果消費者的處理能力大於生產者,那麼消費者就必須等待生產者。為了解決這個問題於是引入了生產者和消費者模式。

什麼是生產者消費者模式
生產者消費者模式是通過一個容器來解決生產者和消費者的強耦合問題。生產者和消費者彼此之間不直接通訊,而通過阻塞佇列來進行通訊,所以生產者生產完資料之後不用等待消費者處理,直接扔給阻塞佇列,消費者不找生產者要資料,而是直接從阻塞佇列裡取,阻塞佇列就相當於一個緩衝區,平衡了生產者和消費者的處理能力。