20 - 進程📄目錄1 進程介紹1.1 含義1.2 進程的狀態2 進程語法結構2.1 Process類參數2.2 常用的屬性2.3 常用的方法2.4 進程間不共享全局變量3 進程間的通信4 進程池(Process Pool)導航連結:
含義:是操作系統進行資源分配和調度的基本單位,是操作系統結構的基礎
一個正在運行的程序或者軟件就是一個進程
程序跑起來就成了進程
❗注意:進程中可以建立多個線程,多進程也可以完成多任務
就緒狀態:運行的條件都已經滿足,正在等待CPU執行
執行狀態:CPU正在執行其功能
等待(阻塞)狀態:等待某些條件滿足,如一個程序休s
xxxxxxxxxx
import time
print("我是Bearbelly") # 程序開始,處於執行狀態
sex = input("輸入性別") # 光標閃動,等待用戶輸入,處於等待狀態
print(sex) # 執行狀態
time.sleep(1) # 延時1秒,等待(阻塞狀態)
👉🏻 multiprocessing模塊提供了Process類代表進程對象
target
:執行的目標任務名,即子進程要執行的任務
args
:以元組的形式傳參
kwargs
:以字典的形式傳參
name:當前進程的別名(默認Process-N)
pid:當前進程的進程編號
xxxxxxxxxx
from multiprocessing import Process
import 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軟件進程編號就是主進程的父編程編號
輸出結果:
xxxxxxxxxx
sing子進程編號:11280, 父進程編號:11278
Antonio is singing.
dance子進程編號:11281, 父進程編號:11278
Victoria is danceing.
p1: First Process
p2: Second Process
p1.pid: 11280
p2.pid: 11281
主進程pid:11278, 主進程的父進程pid:9988
start()
:開始子進程
is_alive()
:判斷子進程是否還活着,存活返回True
,死亡返回False
join()
:主進程等待子進程執行結束
xxxxxxxxxx
from multiprocessing import Process
def 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()阻塞一下
輸出結果:
xxxxxxxxxx
I am eating vegetable.
p1存活狀態:False
p2存活狀態:True
I am drinking beer.
xxxxxxxxxx
from multiprocessing import Process
import time
li = []
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 Queue
q = 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()) # 還有一條數據,返回False
print(q.get())
print(q.empty()) # 沒有數據了,返回True
輸出結果:
xxxxxxxxxx
信息數量滿了沒有:False
You are stupid.
You are dreaming
False
You are losing.
True
案例:
xxxxxxxxxx
from multiprocessing import Process, Queue
import time
li = ["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
結束
案例:
xxxxxxxxxx
from multiprocessing import Pool
import 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上結束
程序結束