一、join讓主進程等待子進程結束後再結束,並回收子進程資源,主進程結束並回收資源python
二、未使用join,而且主進程 「 正常結束 」 ,子進程與主進程一併被回收資源json
一、殭屍進程安全
在子進程結束後,主進程沒有正常結束,子進程PID不會被回收網絡
缺點:操做系統中的PID號是有限的,若有子進程PID 號,沒法正常回收,則會佔用PID號,浪費資源,若PID號滿了,則沒法建立新的進程併發
二、孤兒進程dom
在子進程沒有結束時,主進程沒有 「 正常結束」 ,子進程PID不會被回收優化
操做系統有優化進制(孤兒院):ui
當主進程意外終止,操做系統會檢測是否有正在運行的子進程,會把他們放到孤兒院中,讓操做系統幫忙回收操作系統
當主進程結束時,子進程也必須結束,並回收code
在不使用join的狀況下,使用obj.daemon = True,設置在obj.start()以前,讓主進程結束,子進程也跟着結束,並回收
from multiprocessing import Process import time def data(): print('子進程start') time.sleep(10) print('子進程end') if __name__ == '__main__': obj = Process(target=data) # 守護進程必須在obj.start()以前設置 obj.daemon = True obj.start() time.sleep(1) print('主進程結束') 》》》 # 子進程start # 主進程結束
因爲建立進程是開闢新的內存空間,因此進程之間的數據是相互隔離的
# 進程之間的數據是隔離的 from multiprocessing import Process num = 100 def data1(num): num += 1 # 此處打印的是子進程data1的num,子進程與主進程數據是隔離的 print(num) # 11 def data2(): global num num += 10 # 此處打印的是子進程data2的num,子進程與主進程數據是隔離的 print(num) # 110 if __name__ == '__main__': obj1 = Process(target=data1, args=(10,)) obj2 = Process(target=data2) obj1.start() obj2.start() obj2.join() obj1.join() # 此處打印的是主進程的num,子進程與主進程數據是隔離的 print(num) # 100 print(num) # 100
互斥鎖是用來保證數據讀寫安全的,在修改同一個數據時,同一時間只能有一個任務能夠進行修改,即串行的修改,保證數據安全
# json_data文件中{"num": 0} ,json數據裏面必須是雙引號 from multiprocessing import Process from multiprocessing import Lock import json import time import random lock = Lock() # 查票 def search(name): with open('json_data.json', 'r', encoding= 'utf-8') as f: data_dic = json.load(f) print(f'用戶{name}查看餘票,餘票{data_dic.get("num")}') # 買票 def buy(name): # 網絡延時 with open('json_data.json', 'r', encoding= 'utf-8') as f: data_dic = json.load(f) if data_dic.get('num') > 0: data_dic['num'] -= 1 time.sleep(random.random()) with open('json_data.json', 'w', encoding= 'utf-8') as f: json.dump(data_dic,f) print(f'用戶{name}搶票成功') else: print(f'用戶{name}搶票失敗') def run(name,lock): search(name) # 加鎖 lock.acquire() buy(name) # 釋放鎖 lock.release() if __name__ == '__main__': # 開啓多進程,實現併發 for i in range(10): obj = Process(target=run, args=(f'jason{i},',lock)) obj.start()
隊列(FIFO):先進先出:先存放的數據,就先取出來
堆棧(FILO):先進後出
至關於第三方的管道,能夠存放數據
應用 :讓進程之間的數據能夠交互
有三種調用方式:
使用Queue(5)指的是隊列中只能存放5份數據,默認長度是32,生成一個對象經過obj.put( x )往隊列中放數據,或者使用obj.put_nowait( x )往隊列中存放數據,使用obj.get()或obj.get_nowait()來獲取隊列中的數據
put :只要隊列滿了,就會進入阻塞
put_nowait :隊列滿了,就會報錯
get:只要隊列中有數據,就能獲取數據,若沒有則會進入阻塞
get_nowait : 只要隊列中有數據,就能獲取數據,若沒有則會報錯
from multiprocessing import Queue # multiprocessing提供隊列 先進先出 from multiprocessing import JoinableQueue # 基於 Queue 封裝的隊列 先進先出 import queue # python內置的隊列 先進先出 Queue(5)指的是隊列中只能存放5份數據,默認長度是32
# 第一種: # 生成隊列對象 obj = Queue(5) # 第二種: # 生成隊列對象 obj = JoinableQueue(5) # 第三種: # 生成隊列對象 obj = queen.Queue(5) # 添加數據到隊列中 obj.put('1') print('添加一個數1') obj.put('2') print('添加一個數2') obj.put('3') print('添加一個數3') obj.put('4') print('添加一個數4') obj.put('5') print('添加一個數5') # put :只要隊列滿了,就會進入阻塞 # obj.put('6') # print('添加一個數6') # put_nowait :隊列滿了,就會報錯 # obj.put_nowait('6') # print('添加一個數6') print(obj.get()) print(obj.get()) print(obj.get()) print(obj.get()) print(obj.get()) # get:只要隊列中有數據,就能獲取數據,若沒有則會進入阻塞 # print(obj.get()) # get_nowait : 只要隊列中有數據,就能獲取數據,若沒有則會報錯 # print(obj.get_nowait())
IPC機制:是進程之間實現通訊,使用隊列讓兩個進程之間的數據進行交互,實現進制之間的通訊
from multiprocessing import Process from multiprocessing import JoinableQueue import time def task1(q): x = 100 q.put(x) print(f'添加數據{x}到隊列中') time.sleep(2) # 獲取隊列中的數據 # task2中又放了數據到隊列中被獲取到 print(q.get()) # 200 def task2(q): # 獲取隊列中的數據,task1中先放了數據先獲取到task1中的數據 res = q.get() print(f'獲取的數據{res}') # 獲取的數據100 # 放數據到隊列中 q.put(200) if __name__ == '__main__': q = JoinableQueue(5) # 先放task1數據 p1 = Process(target=task1, args=(q,)) # 再放task2數據 p2 = Process(target=task2, args=(q,)) p1.start() p2.start()
生產者:生產數據的
消費者:使用數據的
有兩種狀況,一、生產者生產的大於消費者所需的,供大於求;二、生產者生產的不夠消費者使用的,供不該求
生產者:往隊列中加數據
消費者:從隊列中取數據
from multiprocessing import JoinableQueue from multiprocessing import Process import time # 生產者:生產數據——》隊列 def producer(name, food, q): msg = f'{name}生產了{food}' # 往隊列中加數據 q.put(food) print(msg) # 消費者: 從隊列中使用數據 def customer(name, q): while True: try: time.sleep(1) # 從隊列中取數據 food = q.get() msg = f'{name}消費了{food}' print(msg) except Exception: break if __name__ == '__main__': # 默認長度32 q = JoinableQueue() # 建立生產者 for i in range(10): p1 = Process(target=producer, args=('tank', f'油條{i}', q)) p1.start() # 建立兩個消費者 c1 = Process(target=customer, args=('Mr沈', q)) c2 = Process(target=customer, args=('shen', q)) c1.start() c2.start()