20 - 進程📄目錄1 進程介紹1.1 含義1.2 進程的狀態2 進程語法結構2.1 Process類參數2.2 常用的屬性2.3 常用的方法2.4 進程間不共享全局變量3 進程間的通信4 進程池(Process Pool)導航連結:
含義:是操作系統進行資源分配和調度的基本單位,是操作系統結構的基礎
一個正在運行的程序或者軟件就是一個進程
程序跑起來就成了進程
❗注意:進程中可以建立多個線程,多進程也可以完成多任務
就緒狀態:運行的條件都已經滿足,正在等待CPU執行
執行狀態:CPU正在執行其功能
等待(阻塞)狀態:等待某些條件滿足,如一個程序休s

xxxxxxxxxximport timeprint("我是Bearbelly") # 程序開始,處於執行狀態sex = input("輸入性別") # 光標閃動,等待用戶輸入,處於等待狀態print(sex) # 執行狀態time.sleep(1) # 延時1秒,等待(阻塞狀態)👉🏻 multiprocessing模塊提供了Process類代表進程對象
target:執行的目標任務名,即子進程要執行的任務
args:以元組的形式傳參
kwargs:以字典的形式傳參
name:當前進程的別名(默認Process-N)
pid:當前進程的進程編號

xxxxxxxxxxfrom multiprocessing import Processimport os # 模塊用於獲取主進程的編號def sing(): # os.getpid():可以用於獲取當前進程編號 # os.getppid():獲取當前父進程編號(ppid: parent pid) print(f"sing子進程編號:{os.getpid()}, 父進程編號:{os.getppid()}") # 父進程的pid就是py文件主進程的pid print('Antonio is singing.')def dance(): print(f"dance子進程編號:{os.getpid()}, 父進程編號:{os.getppid()}") print('Victoria is danceing.')if __name__ == '__main__': # 1. 創建子進程 p1 = Process(target=sing) # 普通創建形式 p2 = Process(target=dance) # p1 = Process(target=sing, name = 'sing') # 4a. 修改進程名的第一種方式:同時指定進程名 # p2 = Process(target=dance, name = 'dance') # 2. 開啟子進程 p1.start() p1.join() p2.start() p2.join() # 4b. 修改子進程名的第二種方式 p1.name = "First Process" p2.name = "Second Process" # 3. 訪問name屬性 print("p1:", p1.name) print("p2:", p2.name) # 5. 查看子進程的進程編號 print("p1.pid:", p1.pid) print("p2.pid:", p2.pid) # 6. 查看主進程的進程編號 print(f"主進程pid:{os.getpid()}, 主進程的父進程pid:{os.getppid()}") # 主進程pid和子進程的父進程pid一樣,兩者是一樣東西 # 主進程的父進程pid就是pycharm軟件的進程編號 # Windows:cmd命令提示符窗口輸入tasklist可以查看電腦裡面進程的命令 # Ctrl + F 查找 # pycharm64軟件進程編號就是主進程的父編程編號輸出結果:
xxxxxxxxxxsing子進程編號:11280, 父進程編號:11278Antonio is singing.dance子進程編號:11281, 父進程編號:11278Victoria is danceing.p1: First Processp2: Second Processp1.pid: 11280p2.pid: 11281主進程pid:11278, 主進程的父進程pid:9988start():開始子進程
is_alive():判斷子進程是否還活着,存活返回True,死亡返回False
join():主進程等待子進程執行結束

xxxxxxxxxxfrom multiprocessing import Processdef eat(food): print(f"I am eating {food}.")def drink(beverage): print(f"I am drinking {beverage}.")if __name__ == '__main__': p1 = Process(target=eat, args=('vegetable',)) # 元組傳參,只有一個變量時,一定要加逗號 p2 = Process(target=drink, args=('beer',)) p1.start() p1.join() # 加了join,主進程處於等待狀態 p2.start() print(f"p1存活狀態:{p1.is_alive()}") # 有join,p1子進程結束後才運行後面的代碼,所以子進程已經死掉,返回False print(f"p2存活狀態:{p2.is_alive()}")# 寫在主進程中判斷存活狀態的時候需要加入join()阻塞一下輸出結果:
xxxxxxxxxxI am eating vegetable.p1存活狀態:Falsep2存活狀態:TrueI am drinking beer.
xxxxxxxxxxfrom multiprocessing import Processimport timeli = []def wdata(n): for i in range(n): li.append(i) time.sleep(0.2) print("寫入的數據是:", li)def rdata(): print("讀取的數據是:", li)# 為什麼要有if __name__?# 1. 防止別人導入文件的時候執行main裡面的方法# 2. 防止windows系統遞歸創建子進程if __name__ == "__main__": p1 = Process(target=wdata, args=(5,)) p2 = Process(target=rdata) p1.start() p1.join() p2.start() # 讀取的數據永遠是空的 # 原因:進程不共享全局變量輸出結果:
xxxxxxxxxx寫入的數據是: [0, 1, 2, 3, 4]讀取的數據是: []q.put():放入數據
q.get():取出數據
q.empty():判斷隊列是否為空
q.qsize():返回當前隊列包含的消息數量(似乎在mac上無法用)
q.full():判斷隊列是否滿了

xxxxxxxxxx# 初始化一個隊列對象from multiprocessing import Queueq = Queue(3) # 最多可以接收3條消息,沒寫或者是負值就代表沒有上限,直至內存的盡頭q.put("You are stupid.")q.put("You are dreaming")print(f"信息數量滿了沒有:{q.full()}")q.put("You are losing.")# q.put("You have losed.") # 最多接收3條,就不能再輸入第4條# print(q.qsize()) # 似乎在mac上無法用print(q.get()) # 獲取隊列的一條消息,然後將其從隊列中移除print(q.get())print(q.empty()) # 還有一條數據,返回Falseprint(q.get())print(q.empty()) # 沒有數據了,返回True輸出結果:
xxxxxxxxxx信息數量滿了沒有:FalseYou are stupid.You are dreamingFalseYou are losing.True
案例:
xxxxxxxxxxfrom multiprocessing import Process, Queueimport timeli = ["Victoria", "Antonio", "Billy", "Paul", "Anne"]def wdata(q1): for name in li: print(f"寫入: {name}") q1.put(name) time.sleep(0.3) q1.put(None) # 結束信號def rdata(q2): while True: item = q2.get() if item is None: break print(f"讀取: {item}") print("結束")if __name__ == "__main__": queue = Queue() p1 = Process(target=wdata, args=(queue,)) p2 = Process(target=rdata, args=(queue,)) p1.start() p2.start() p1.join() p2.join()輸出結果:
xxxxxxxxxx寫入: Victoria讀取: Victoria寫入: Antonio讀取: Antonio寫入: Billy讀取: Billy寫入: Paul讀取: Paul寫入: Anne讀取: Anne結束
案例:
xxxxxxxxxxfrom multiprocessing import Poolimport time, os
def task(task_id): print("子進程編號:{},工作在任務{}上開始".format(os.getpid(), task_id)) time.sleep(2) print("子進程編號:{},工作在任務{}上結束".format(os.getpid(), task_id))
if __name__ == "__main__": print("程序開始") # 創建進程池 pool = Pool() # Pool(processes=N)中的N,為手動控制同時運行的進程數目,可以填上合適數字 # 如果是pool = Pool(),就是默認同時運行進程數 for i in range(20): # apply:以阻塞的形式調用func函數 pool.apply_async(task, args=(i,)) # for循環可以換成: # pool.map_async(task, range(20)) pool.close() # 關閉進程池 pool.join() # 等待子進程執行完畢 print("程序結束")輸出結果:
xxxxxxxxxx程序開始子進程編號:12557,工作在任務0上開始子進程編號:12554,工作在任務1上開始子進程編號:12556,工作在任務2上開始子進程編號:12560,工作在任務3上開始子進程編號:12558,工作在任務4上開始子進程編號:12561,工作在任務5上開始子進程編號:12555,工作在任務6上開始子進程編號:12559,工作在任務7上開始子進程編號:12557,工作在任務0上結束子進程編號:12557,工作在任務8上開始子進程編號:12554,工作在任務1上結束子進程編號:12554,工作在任務9上開始子進程編號:12556,工作在任務2上結束子進程編號:12556,工作在任務10上開始子進程編號:12558,工作在任務4上結束子進程編號:12560,工作在任務3上結束子進程編號:12560,工作在任務11上開始子進程編號:12558,工作在任務12上開始子進程編號:12561,工作在任務5上結束子進程編號:12561,工作在任務13上開始子進程編號:12555,工作在任務6上結束子進程編號:12559,工作在任務7上結束子進程編號:12555,工作在任務14上開始子進程編號:12559,工作在任務15上開始子進程編號:12554,工作在任務9上結束子進程編號:12557,工作在任務8上結束子進程編號:12557,工作在任務16上開始子進程編號:12554,工作在任務17上開始子進程編號:12556,工作在任務10上結束子進程編號:12556,工作在任務18上開始子進程編號:12559,工作在任務15上結束子進程編號:12559,工作在任務19上開始子進程編號:12558,工作在任務12上結束子進程編號:12561,工作在任務13上結束子進程編號:12555,工作在任務14上結束子進程編號:12560,工作在任務11上結束子進程編號:12557,工作在任務16上結束子進程編號:12554,工作在任務17上結束子進程編號:12556,工作在任務18上結束子進程編號:12559,工作在任務19上結束程序結束