進程進階

進程進階

一、子進程回收資源的兩種方式

​ 一、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)

隊列(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機制

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()
相關文章
相關標籤/搜索