目錄
-
Python并發編程03/僵尸孤兒進程,互斥鎖,進程之間的通信
- 1.昨日回顧
-
2.僵尸進程和孤兒進程
- 2.1僵尸進程
- 2.2孤兒進程
- 2.3僵尸進程如何解決?
-
3.互斥鎖,鎖
- 3.1互斥鎖的應用
- 3.2Lock與join的區別
-
4.進程之間的通信
- 進程在內存級別是隔離的
- 4.1基于文件通信 (搶票系統)
- 4.2基于隊列通信
Python并發編程03/僵尸孤兒進程,互斥鎖,進程之間的通信
1.昨日回顧
1.創建進程的兩種方式: 函數, 類.
2.pid: os.getpid() os.getppid()
tasklist
tasklist| findstr 進程名
3.進程與進程之間是有物理隔離: 不能共享內存的數據.(lock,隊列)
4.join阻塞: 讓主進程等待子進程結束之后,在執行.
5.其他屬性: terminate() is_alive() name,
6.守護進程: 將子進程設置成守護進程,當主進程結束了,子進程就馬上結束.
2.僵尸進程和孤兒進程
2.1僵尸進程
僵尸進程:一個進程使用fork創建子進程,如果子進程退出,而父進程并沒有調用wait或waitpid獲取子進程的狀態信息,那么子進程的進程描述符仍然保存在系統中,這種進程稱之為僵尸進程.
#基于unix環境(linux,macOS)
#主進程需要等待子進程結束之后,主進程才結束
主進程時刻監測子進程的運行狀態,當子進程結束之后,一段時間之內,將子進程進行回收.
#為什么主進程不在子進程結束后馬上對其回收呢?
# 1. 主進程與子進程是異步關系.主進程無法馬上捕獲子進程什么時候結束.
# 2. 如果子進程結束之后馬上再內存中釋放資源,主進程就沒有辦法監測子進程的狀態了.
#unix針對于上面的問題,提供了一個機制.
#所有的子進程結束之后,立馬會釋放掉文件的操作鏈接,內存的大部分數據,但是會保留一些內容: 進程號,結束時間,運行狀態,等待主進程監測,回收.
僵尸進程: 所有的子進程結束之后,在被主進程回收之前,都會進入僵尸進程狀態.
#僵尸進程有無危害???
#如果父進程不對僵尸進程進行回收(wait/waitpid),產生大量的僵尸進程,這樣就會占用內存,占用進程pid號.
2.2孤兒進程
#父進程由于某種原因結束了,但是你的子進程還在運行中,這樣你的這些子進程就成了孤兒進程.你的父進程如果結束了,你的所有的孤兒進程就會被init進程的回收,init就變成了你的父進程,對你進行回收.
2.3僵尸進程如何解決?
#父進程產生了大量子進程,但是不回收,這樣就會形成大量的僵尸進程,解決方式就是直接殺死父進程,將所有的僵尸進程變成孤兒進程進程,由init進行回收.
3.互斥鎖,鎖
3.1互斥鎖的應用
# 三個同事 同時用一個打印機打印內容.
# 三個進程模擬三個同事, 輸出平臺模擬打印機.
# 版本一:
# from multiprocessing import Process
# import time
# import random
# import os
#
# def task1():
# print(f'{os.getpid()}開始打印了')
# time.sleep(random.randint(1,3))
# print(f'{os.getpid()}打印結束了')
#
# def task2():
# print(f'{os.getpid()}開始打印了')
# time.sleep(random.randint(1,3))
# print(f'{os.getpid()}打印結束了')
#
# def task3():
# print(f'{os.getpid()}開始打印了')
# time.sleep(random.randint(1,3))
# print(f'{os.getpid()}打印結束了')
#
# if __name__ == '__main__':
#
# p1 = Process(target=task1)
# p2 = Process(target=task2)
# p3 = Process(target=task3)
#
# p1.start()
# p2.start()
# p3.start()
# 現在是所有的進程都并發的搶占打印機,
# 并發是以效率優先的,但是目前我們的需求: 順序優先.
# 多個進程共強一個資源時, 要保證順序優先: 串行,一個一個來.
# 版本二:
# from multiprocessing import Process
# import time
# import random
# import os
#
# def task1(p):
# print(f'{p}開始打印了')
# time.sleep(random.randint(1,3))
# print(f'{p}打印結束了')
#
# def task2(p):
# print(f'{p}開始打印了')
# time.sleep(random.randint(1,3))
# print(f'{p}打印結束了')
#
# def task3(p):
# print(f'{p}開始打印了')
# time.sleep(random.randint(1,3))
# print(f'{p}打印結束了')
#
# if __name__ == '__main__':
#
# p1 = Process(target=task1,args=('p1',))
# p2 = Process(target=task2,args=('p2',))
# p3 = Process(target=task3,args=('p3',))
#
# p2.start()
# p2.join()
# p1.start()
# p1.join()
# p3.start()
# p3.join()
# 我們利用join 解決串行的問題,保證了順序優先,但是這個誰先誰后是固定的.
# 這樣不合理. 你在爭搶同一個資源的時候,應該是先到先得,保證公平.
# 版本3:
from multiprocessing import Process
from multiprocessing import Lock
import time
import random
import os
def task1(p,lock):
'''
一把鎖不能連續鎖兩次
lock.acquire()
lock.acquire()
lock.release()
lock.release()
'''
lock.acquire()
print(f'{p}開始打印了')
time.sleep(random.randint(1,3))
print(f'{p}打印結束了')
lock.release()
def task2(p,lock):
lock.acquire()
print(f'{p}開始打印了')
time.sleep(random.randint(1,3))
print(f'{p}打印結束了')
lock.release()
def task3(p,lock):
lock.acquire()
print(f'{p}開始打印了')
time.sleep(random.randint(1,3))
print(f'{p}打印結束了')
lock.release()
if __name__ == '__main__':
mutex = Lock()
p1 = Process(target=task1,args=('p1',mutex))
p2 = Process(target=task2,args=('p2',mutex))
p3 = Process(target=task3,args=('p3',mutex))
p2.start()
p1.start()
p3.start()
3.2Lock與join的區別
#共同點: 都可以把并發變成串行, 保證了順序.
#不同點: join人為設定順序,lock讓其爭搶順序,保證了公平性.
4.進程之間的通信
進程在內存級別是隔離的
4.1基于文件通信 (搶票系統)
# 搶票系統.
# 1. 先可以查票.查詢余票數. 并發
# 2. 進行購買,向服務端發送請求,服務端接收請求,在后端將票數-1,返回到前端. 串行.
# from multiprocessing import Process
# import json
# import time
# import os
# import random
#
#
# def search():
# time.sleep(random.randint(1,3)) # 模擬網絡延遲(查詢環節)
# with open('ticket.json',encoding='utf-8') as f1:
# dic = json.load(f1)
# print(f'{os.getpid()} 查看了票數,剩余{dic["count"]}')
#
#
# def paid():
# with open('ticket.json', encoding='utf-8') as f1:
# dic = json.load(f1)
# if dic['count'] > 0:
# dic['count'] -= 1
# time.sleep(random.randint(1,3)) # 模擬網絡延遲(購買環節)
# with open('ticket.json', encoding='utf-8',mode='w') as f1:
# json.dump(dic,f1)
# print(f'{os.getpid()} 購買成功')
#
# def task():
# search()
# paid()
#
#
# if __name__ == '__main__':
#
# for i in range(6):
# p = Process(target=task)
# p.start()
# 當多個進程共強一個數據時,如果要保證數據的安全,必須要串行.
# 要想讓購買環節進行串行,我們必須要加鎖處理.
#
# from multiprocessing import Process
# from multiprocessing import Lock
# import json
# import time
# import os
# import random
#
#
# def search():
# time.sleep(random.randint(1,3)) # 模擬網絡延遲(查詢環節)
# with open('ticket.json',encoding='utf-8') as f1:
# dic = json.load(f1)
# print(f'{os.getpid()} 查看了票數,剩余{dic["count"]}')
#
#
# def paid():
# with open('ticket.json', encoding='utf-8') as f1:
#
# dic = json.load(f1)
# if dic['count'] > 0:
# dic['count'] -= 1
# time.sleep(random.randint(1,3)) # 模擬網絡延遲(購買環節)
# with open('ticket.json', encoding='utf-8',mode='w') as f1:
# json.dump(dic,f1)
# print(f'{os.getpid()} 購買成功')
#
#
# def task(lock):
# search()
# lock.acquire()
# paid()
# lock.release()
#
# if __name__ == '__main__':
# mutex = Lock()
# for i in range(6):
# p = Process(target=task,args=(mutex,))
# p.start()
# 當很多進程搶一個資源(數據)時, 你要保證順序(數據的安全),一定要串行.
# 互斥鎖: 可以公平性的保證順序以及數據的安全.
# 基于文件的進程之間的通信:
# 效率低.
# 自己加鎖麻煩而且很容易出現死鎖.
4.2基于隊列通信
隊列: 把隊列理解成一個容器,這個容器可以承載一些數據,
隊列的特性: 先進先出永遠保持這個數據. FIFO(first in first out).
# from multiprocessing import Queue
# q = Queue()
# def func():
# print('in func')
# q.put(1)
# q.put('alex')
# q.put([1,2,3])
# q.put(func)
#
#
# print(q.get())
# print(q.get())
# print(q.get())
# f = q.get()
# f()
# from multiprocessing import Queue
# q = Queue(3)
#
# q.put(1)
# q.put('alex')
# q.put([1,2,3])
# # q.put(5555) # 當隊列滿了時,在進程put數據就會阻塞.
# # q.get()
#
# print(q.get())
# print(q.get())
# print(q.get())
# print(q.get()) # 當數據取完時,在進程get數據也會出現阻塞,直到某一個進程put數據.
# from multiprocessing import Queue
# q = Queue(3) # maxsize
#
# q.put(1)
# q.put('alex')
# q.put([1,2,3])
# q.put(5555,block=False)
#
# print(q.get())
# print(q.get())
# print(q.get())
# print(q.get(timeout=3)) # 阻塞3秒,3秒之后還阻塞直接報錯.
# print(q.get(block=False))
# block=False 只要遇到阻塞就會報錯.
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
