20181229(守護程序,互斥鎖,IPC,生產者和消費者模型)
阿新 • • 發佈:2018-12-29
一、守護程序
守護程序:一個程序B守護另一個程序A,當被守護的程序A結束,程序B也就結束了。(不一定同生,但會同死)
兩個特點:
①守護程序會在主程序程式碼執行結束後就終止
②守護程序內無法再開啟子程序,否則丟擲異常。
注意:程序之間是互相獨立的,主程序程式碼執行結束,守護程序隨即終止
應用場景:如果主程序認為一旦自己結束,子程序也就沒有繼續執行的必要了,就可以將子程序設定為守護程序。(例如:qq正在呼叫自身的下載檔案功能,但是此時退出了qq,下載程序也就可以直接關閉了)
方法為:process.daemon=True,必須放置在子程序開啟前。
from multiprocessing import Process
import time
def task(name):
print('%s is running' % name)
time.sleep(3)
print('%s is running' % name) # 等待三秒的時候,被守護程序已經執行完了,所以守護程序會被回收,此句話就不會列印了。
if __name__ == '__main__':
obj = Process(target=task, args=('守護程序',))
obj.daemon=True # 必須在start前設定,會限制p建立子程序,且父程序結束子程序馬上殉葬結束。
obj.start() # 傳送訊號給作業系統
time.sleep(1)
print('被守護程序')
輸出結果:
守護程序 is running
被守護程序
二、互斥鎖
互斥鎖:將併發變為序列(即一個一個執行)
from multiprocessing import Process,Lock
import time,random
mutex=Lock() # 例項化互斥鎖,也可以放到main下面。
# 強調:必須是lock.acquire()一次,然後 lock.release()釋放一次,才能繼續lock.acquire(),不能連續的lock.acquire(),否則會形成阻塞,程式卡死。
def task1(lock):
lock.acquire() # 得到這把鎖,此時其他的同級子程序都只能等待當前程序將鎖釋放之後才有機會執行。
print('task1:名字是egon')
time.sleep(random.randint(1,3))
print('task1:性別是male')
time.sleep(random.randint(1,3))
print('task1:年齡是18')
lock.release() # 鎖用完之後,一定要釋放,否則其他子程序無法進行
def task2(lock):
lock.acquire() # 是一個阻塞的函式 會等到別的程序釋放鎖才能繼續執行
print('task2:名字是alex')
time.sleep(random.randint(1,3))
print('task2:性別是male')
time.sleep(random.randint(1,3))
print('task2:年齡是78')
lock.release()
def task3(lock):
lock.acquire()
print('task3:名字是lxx')
time.sleep(random.randint(1,3))
print('task3:性別是female')
time.sleep(random.randint(1,3))
print('task3:年齡是30')
lock.release()
if __name__ == '__main__':
p1=Process(target=task1,args=(mutex,)) # 建立程序並傳參,將鎖傳給各個子程序
p2=Process(target=task2,args=(mutex,))
p3=Process(target=task3,args=(mutex,))
p1.start() # 三個子程式都能啟動,但是一旦碰到鎖,誰先搶到誰先執行,其他的要等。
p2.start()
p3.start()
互斥鎖與join的區別:
二者原理都一樣,都是將併發變為序列,從而保證資料增刪改查的有序性,不至於讓資料發生錯亂。
二者的區別在於join是按照人為指定順序執行,程序執行順序是固定的,而互斥鎖是所有程序公平競爭,誰先搶到鎖,誰就能先執行;且互斥鎖可以指定某一部分程式碼序列,其餘部分程式碼併發,而join則是整個子程序程式碼完全序列。
互斥鎖的本質是一個布林型別的資料,在執行程式碼前,會先判斷這個值。
互斥鎖在搶票中的應用:
import json
from multiprocessing import Process,Lock
import time
import random
# 檢視剩餘票數
def check_ticket(usr):
time.sleep(random.randint(1,3))
with open("ticket.json","r",encoding="utf-8") as f: # 提前做好json檔案,做成字典。
dic = json.load(f)
print("%s檢視 剩餘票數:%s" % (usr,dic["count"]))
def buy_ticket(usr):
with open("ticket.json","r",encoding="utf-8") as f:
dic = json.load(f)
if dic["count"] > 0:
time.sleep(random.randint(1,3))
dic["count"] -= 1
with open("ticket.json", "w", encoding="utf-8") as f2: #
json.dump(dic,f2)
print("%s 購票成功!" % usr)
else:
print("票被搶走了!%s購票失敗" % usr)
def task(usr,lock):
check_ticket(usr) # 查票可以併發
lock.acquire() # 排票就要串行了
buy_ticket(usr)
lock.release() # 買好票後要釋放鎖
if __name__ == '__main__':
lock = Lock()
for i in range(10): # 啟動10個程序去買票,模仿10個人。
p = Process(target=task,args=("使用者%s" % i,lock))
p.start()
輸出結果: #每次結果可能都不一致
使用者0檢視 剩餘票數:1
使用者2檢視 剩餘票數:1
使用者3檢視 剩餘票數:1
使用者1檢視 剩餘票數:1
使用者0 購票成功!
票被搶走了!使用者2購票失敗
票被搶走了!使用者3購票失敗
票被搶走了!使用者1購票失敗
使用者5檢視 剩餘票數:0
票被搶走了!使用者5購票失敗
使用者4檢視 剩餘票數:0
票被搶走了!使用者4購票失敗
使用者7檢視 剩餘票數:0
票被搶走了!使用者7購票失敗
使用者6檢視 剩餘票數:0
票被搶走了!使用者6購票失敗
使用者9檢視 剩餘票數:0
票被搶走了!使用者9購票失敗