1 什么是行程
行程是系統進行資源分配和調度的基本單位,行程表示程式正在執行的程序,是‘活的’,而程式就是一推躺在硬碟上的代碼,是‘死的’,
2 行程的調度
1.先來先服務調度演算法:對長作業有利,對短作業無利
2.短作業優先調度演算法:對短作業有利,對長作業無利
3.時間片輪轉法+多級反饋佇列
該方法是指,將時間片切成n份,每一份表示一個時間片,這些時間片有一個優先級順序,最上面的優先執行,一個長任務第一個時間片沒有完成會被放到第二個,如果第一個時間片有來任務會優先等第一個執行完在執行第二個,
3 行程的三狀態圖

4. 如何創建行程
4.1 行程創建的第一種方式(掌握)
from multiprocessing import Process # 匯入行程模塊
import time
# 子行程函式
def func(name):
print('支線%s'% name)
time.sleep(3)
print('over%s'% name)
# windows下創建行程,一定要在main下面創建
# 因為windows創建行程類似于模塊匯入的方式,會從上往下依次執行,如果放在main外面,會一直創建行程下去
# linux系統中只是將代碼拷貝一份,因此不需要在main下面創建
# main表示當該檔案是執行檔案時才會被運行,該檔案是匯入的形式時不會被運行
if __name__ == '__main__':
# 1.創建行程物件
# 引數1:需要創建行程的目標函式;
# 引數2:需要給函式傳的引數是一個元組形式,當需要傳的引數是一個時,注意加一個,
p = Process(target=func,args=('yun',))
# 2.開啟行程,告訴作業系統創建行程,作業系統會去申請一個記憶體空間,把子行程丟進去執行
p.start()
# 3.下面是主行程的執行
print('主')
4.2 創建行程的第二種方式
from multiprocessing import Process
import time
# 1.創建一個類,該類繼承Process類
class MyProcess(Process):
# 2.類中子行程的函式名必須是run
def run(self):
print('hello')
time.sleep(1)
print('gun')
if __name__ == '__main__':
# 3.產生類的物件
p = MyProcess()
# 4.開啟行程
p.start()
print('主')
總結:
1.創建行程實際上就是在記憶體中申請了一塊記憶體空間,將代碼丟進去運行
2.一個行程產生一個記憶體空間,多個行程產生多個記憶體空間
3.行程之間默認是無法進行資料互動的,如果需要互動需要借助第三方模塊,在子行程修改全域變數,全域變數不會改變
4.3 行程中join方法
join方法是用來讓主行程代碼等待呼叫join的子行程代碼運行結束之后,在運行主行程!
p1.join()
p2.join()
p3.join()
print('主')
如果p2和p3不呼叫join方法,主行程就不會等待其運行結束后再運行!!!
4.4 行程物件和其他方法
一臺計算機上面運行著很多行程,那么計算機是如何區分并管理著這些行程,計算機會給這些行程各自分配一個pid
在windows終端,可以通過tasklist命令查看所有的行程pid
tasklist |findstr PID 查看具體行程的命令
在mac電腦,可以通過ps aux查看
ps aux|grep PID 查看具有行程的命令
行程的其他方法:
from multiprocessing import Process,current_process
import time
import os
def func():
# current_process().pid 獲取當前行程的行程id
print('%s 正在運行'% current_process().pid)
time.sleep(2)
if __name__ == '__main__':
p = Process(target=func)
p.start()
# os.getpid()也是獲取當前行程id的方法
p.terminate() # 殺死當前行程,系統幫您殺死該行程,需要一定的時間,所有下面的is_alive可能為true
print(p.is_alive()) # 判斷當前行程是否存活
print('主',os.getpid())
# os.getppid()是獲取當前父id的方法
print('主主',os.getppid())
4.5 僵尸行程與孤兒行程
僵尸行程:
當子行程死了,子行程并不會立即占用的行程id號,因為需要讓父行程查看到子行程的id、運行時間等資訊,所有行程會步入僵尸行程
回收子行程的id號:1,負行程呼叫join()方法 2.父行程等待子行程運行完畢
孤兒行程:
子行程存活,父行程意外死亡,
作業系統會幫你自動回收子行程的資源
4.6 守護行程
"你死我也不獨活" p.daemon = True 方法設定守護行程
from multiprocessing import Process,current_process
import time
def func():
print('奴隸活著')
time.sleep(2)
print('奴隸死去')
if __name__ == '__main__':
p = Process(target=func)
p.daemon = True # 將p這個子行程設定成守護行程,這一句話一定要放在start前面,否則保錯
p.start()
print('主人死了')
4.7 行程中的互斥鎖
多個行程操作同一個資料的時候,很可能會出現資料錯亂的問題
針對上述問題,解決方案就是加鎖處理:將并發變成串行,犧牲效率保證資料的安全準確
# 1.匯入鎖模塊
from multiprocessing import Process LOCK
# 2.在主行程中生成一把鎖,讓所有子行程去搶這把鎖,mutex 需要傳入對應函式的引數里面
mutex = LOCK()
# 3.在需要加鎖的功能上面
mutex.acquire()
# 4.在功能執行完的下面,解鎖
mutex.release()
總結:
1.鎖不要輕易使用,容易造成鎖死的現象
2.鎖只在需要爭搶資料的時候使用,保證資料的安全
4.8 行程間的通信
行程之間是無法相互通信的,因此需要采用第三方模塊佇列queue,
注意:佇列中的資料是先進先出的,
# 匯入佇列模塊
import queue
# 也可以用下面這種方式之間匯入到佇列類
from multiprocessing import Queue
# 1.生成一個佇列物件
q = queue.Queue(3) # 括號內可以傳數字,表示佇列可以最大存放的資料量,不傳有一個很大的默認值
# 2.給佇列存資料
q.put(111)
print(q.full()) # 判斷當前佇列是否存滿
q.put(222)
print(q.empty()) # 判斷當前佇列是否為空
q.put(333)
print(q.full())
# q.put(444) # 當給佇列存的資料個數超過佇列的最大存放數,佇列會進入阻塞狀態等待位置
# 3.從佇列中取值
v1 = q.get()
v2 = q.get()
v3 = q.get()
# v4 = q.get() 當佇列中沒有資料的時候,在次取值會使得佇列進入阻塞
v5 = q.get_nowait() # 當佇列中沒有資料可取的時候,就報錯
v6 = q.get(timeout=3) # 沒有資料原地等待3秒,然后報錯
print(v1,v2,v3)
# 總結:
'''
q.full()
q.empty()
q.get_nowait()
這三個方法在多行程下是不精確的
'''
IPC機制:
1.子行程和主行程之間的通信
2.子行程和子行程之間的通信
from multiprocessing import Queue,Process
def cosumer1(q):
# 在子行程中存資料
q.put('我是佇列存的資訊')
print('子行程1')
def cosumer2(q):
# 在子行程中取資料
print(q.get())
if __name__ == '__main__':
q = Queue()
p = Process(target=cosumer1,args=(q,))
p1 = Process(target=cosumer2,args=(q,))
p.start()
p1.start()
# 在主行程取出資料
# print(q.get())
5. 行程的綜合應用--生產者消費者模型
from multiprocessing import Queue,Process,JoinableQueue
import time
import random
# 生產者子行程
def producer(name,food,q):
for i in range(5):
print('%s生產了%s%s'%(name,food,i))
time.sleep(random.randint(1,3))
q.put(food)
def consumer(name,q):
# 消費者一直在吃,進入回圈
while True:
food = q.get() # 當佇列中沒有東西的時候,該子行程會被卡住,進入阻塞狀態
print('%s吃了%s'%(name,food))
q.task_done() # 該方法屬于JoinableQueue,作用是告訴佇列你已經從佇列中取出一個資料并且處理完畢了
if __name__ == '__main__':
# 將q = Queue()改成下面的方法創建佇列
q = JoinableQueue()
# 兩個生產者,分別生產的東西放進佇列中
p1 = Process(target=producer,args=('zhang','包子',q))
p2 = Process(target=producer, args=('yang', '粥', q))
# 消費者從佇列中取出東西吃掉
c1 = Process(target=consumer,args=('www',q))
p1.daemon = True # 守護主行程,主行程結束殺死子行程
p2.daemon = True
c1.daemon = True
p1.start()
p2.start()
c1.start()
p1.join()
p2.join() # 等待生產者生產完畢在執行下面的代碼
q.join() # 等待佇列中所有的資料被取完之后再執行下述代碼
# JoinableQueue類
"""
該類是在queue類上的基礎上添加了一個計數器,每當往佇列中存放一個資料時,計數器會加1;
當你呼叫task_done時,計數器減1
q.join() 等待計數器為0的時候在執行該方法下面的代碼
"""
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/502547.html
標籤:Python
