執行緒 、進程、協程的基本使用
- 2021 年 1 月 21 日
- 筆記
進程(Process)、執行緒(Thread)、協程(Coroutine)的概念:
進程:
就是正在運行的程式,它是作業系統中,資源分配的最小單位.,
資源分配:分配的是cpu和記憶體等物理資源。
進程號是進程的唯一標識。
默認情況下一個進程只有一個執行緒,在進程裡面可以創建多個執行緒。
執行緒:
cpu執行程式的最小單位, 通過執行緒去執行進程中程式碼, 執行緒是執行程式碼的分支,
執行緒是依附在進程裡面的, 沒有進程就沒有執行緒,
同一個程式執行兩次之後是兩個進程
進程和進程之間的關係: 數據彼此隔離,通過socket通訊
協程:
協程是一種用戶態的輕量級執行緒,協程的調度完全由用戶控制。協程擁有自己的暫存器上下文和棧。協程調度切換時,將暫存器上下文和棧保存到其他地方,在切回來的時候,恢復先前保存的暫存器上下文和棧,直接操作棧則基本沒有內核切換的開銷,可以不加鎖的訪問全局變數,所以上下文的切換非常快。
協程在子程式內部可中斷的,然後轉而執行別的子程式,在適當的時候再返回來接著執行。
並行和並發
- 並發:一個cpu同一時間不停執行多個程式
- 並行:多個cpu同一時間不停執行多個程式
同步和非同步
- 同步是指代在程式執行多個任務時,按部就班的依次執行,必須上一個任務執行完有了結果以後,才會執行下一個任務。
- 非同步是指代在程式執行多個任務時,沒有先後依序,可以同時執行,所以在執行上一個任務時不會等待結果,直接執行下一個任務。一般最終在下一個任務中通過狀態的改變或者通知、回調的方式來獲取上一個任務的執行結果。
cpu的進程調度方法
# 先來先服務fcfs(first come first server):先來的先執行
# 短作業優先演算法:分配的cpu多,先把短的算完
# 時間片輪轉演算法:每一個任務就執行一個時間片的時間.然後就執行其他的.
# 多級回饋隊列演算法
越是時間長的,cpu分配的資源越少,優先順序靠後
越是時間短的,cpu分配的資源越多
進程的性質:
- 進程之間的數據彼此隔離
- 多個進程之間是非同步並發
–進程(Process):
進程的基本使用:
import os, time, random
from multiprocessing import Process
def func(n):
time.sleep(random.randrange(3))
print("數字{}<=>1.子進程id>>{},2父進程id>>{}".format(n, os.getpid(), os.getppid()))
if __name__ == "__main__":
for i in range(1, 11):
# 創建子進程,返回進程對象,執行func這個任務
p = Process(target=func, args=(i,)) # args=(i,)傳遞參數
# 調用子進程
p.start() # 可簡寫成 Process(target=func, args=(i,)).start()
print("主進程執行結束了....")
print(os.getpid()) # os.getpid()進程號
運行視圖:
運行視圖不唯一,因為多個進程之間是非同步並發
進程的join 函數:
- join 等待當前子進程全部執行完畢之後,主進程在執行(用來同步子父進程的)
例:
p = Process(target=func,args=(i,))
p.join()
同步 非同步 / 阻塞 非阻塞
- 同步:必須等我這件事幹完了,你在干,只有一條主線,就是同步
- 非同步:沒等我這件事情幹完,你就在幹了,有兩條主線,就是非同步
- 阻塞:比如程式碼有了input,就是阻塞,必須要輸入一個字元串,否則程式碼不往下執行
- 非阻塞:沒有任何等待,正常程式碼往下執行.
- 同步阻塞 :效率低,cpu利用不充分
- 非同步阻塞 :比如socketserver,可以同時連接多個,但是彼此都有recv
- 同步非阻塞:沒有類似input的程式碼,從上到下執行.默認的正常情況程式碼
事件 (Event)
- 非同步非阻塞:效率是最高的,cpu過度充分,過度發熱 液冷
事件 (Event)阻塞事件 :
『』』
e = Event()生成事件對象e
e.wait()動態給程式加阻塞 , 程式當中是否加阻塞完全取決於該對象中的is_set() [默認返回值是False]
# 如果是True 不加阻塞
# 如果是False 加阻塞
# 阻塞事件 :
e = Event()生成事件對象e
e.wait()動態給程式加阻塞 , 程式當中是否加阻塞完全取決於該對象中的is_set() [默認返回值是False]
# 如果是True 不加阻塞
# 如果是False 加阻塞
# 控制這個屬性的值
# set()方法 將這個屬性的值改成True
# clear()方法 將這個屬性的值改成False
# is_set()方法 判斷當前的屬性是否為True (默認上來是False)
Event_test.py:
在這裡插入程式碼片
控制這個屬性的值
# set()方法 將這個屬性的值改成True
# clear()方法 將這個屬性的值改成False
# is_set()方法 判斷當前的屬性是否為True (默認上來是False)
在這裡插入程式碼片
場景在多任務當中
同步:必須等我這件事幹完了,你在干,只有一條主線,就是同步
非同步:沒等我這件事情幹完,你就在幹了,有兩條主線,就是非同步
阻塞:比如程式碼有了input,就是阻塞,必須要輸入一個字元串,否則程式碼不往下執行
非阻塞:沒有任何等待,正常程式碼往下執行.
# 同步阻塞 :效率低,cpu利用不充分
# 非同步阻塞 :比如socketserver,可以同時連接多個,但是彼此都有recv
# 同步非阻塞:沒有類似input的程式碼,從上到下執行.默認的正常情況程式碼
# 非同步非阻塞:效率是最高的,cpu過度充分,過度發熱 液冷
守護進程
守護進程守護的是主進程,如果主進程中的所有程式碼執行完畢了,
當前這個守護進程會被立刻殺死,立刻終止.
語法:
進程.daemon = True 設置當前這個進程為守護進程
必須寫在start()調用進程之前進行設置
默認:主進程會默認等待所有子進程執行結束之後,在關閉程式,釋放資源
程式碼:
from multiprocessing import Process
import time
# (3) 守護進程實際用途: 監控報活
# 守護進行
def alive():
while True:
print("給監控的總伺服器發消息,報告自己的存活狀態, i am alive~")
time.sleep(1)
# 執行任務
def func():
while True:
try:
time.sleep(1)
raise RuntimeError
print("當前5號伺服器功能:對日誌進行數據分析.... ")
except:
break
# pass
if __name__ == "__main__":
# 創建2個子進程
p1 = Process(target=alive)
p2 = Process(target=func)
# 設置p1為守護進程
# p1.daemon = True
p1.start()
p2.start()
# 必須等到p2任務執行結束之後,在向下執行.
p2.join()
print("當前伺服器狀態異常 ... ")
沒有設置守護進程視圖:
設置守護進程視圖:
#可以給子進程貼上守護進程的名字,該進程會隨著主進程程式碼執行完畢而結束(為主進程守護)
(1)守護進程會在主進程程式碼執行結束後就終止
(2)守護進程內無法再開啟子進程,否則拋出異常(了解)
鎖(Lock)
上鎖和解鎖是一對,只上鎖不解鎖會發生死鎖現象(程式碼阻塞,不往下執行了)
互斥鎖 : 互斥鎖是進程之間的互相排斥,誰先搶到這個鎖資源就先使用,後搶到後使用
訊號量:Semaphore 本質上就是鎖,只不過可以控制上鎖的數量
look:
lock.acquire()# 上鎖
lock.release()# 解鎖
# 創建一把鎖
lock = Lock()
# 上鎖
lock.acquire()
# 連續上鎖不解鎖是死鎖
# lock.acquire() error
print("廁所中...")
# 解鎖
lock.release()
print("執行程式 ... ")
Semaphore:
from multiprocessing import Semaphore,Process
import time,random
sem = Semaphore(4)
sem.acquire()
# sem.acquire()
# sem.acquire()
# sem.acquire()
# sem.acquire() # 上第五把鎖出現死鎖狀態.
print("執行響應的操作")
sem.release()
"""
# 總結:
Semaphore 可以設置上鎖的數量
同一時間最多允許幾個進程上鎖
創建進程的時候,是非同步並發
執行任務的時候,遇到鎖會變成同步程式.
"""
lock.acquire()# 上鎖
lock.release()# 解鎖
#同一時間允許一個進程上一把鎖 就是Lock
加鎖可以保證多個進程修改同一塊數據時,同一時間只能有一個任務可以進行修改,即串列的修改,沒錯,速度是慢了,但犧牲速度卻保證了數據安全。
#同一時間允許多個進程上多把鎖 就是[訊號量Semaphore]
訊號量是鎖的變形: 實際實現是 計數器 + 鎖,同時允許多個進程上鎖
# 互斥鎖Lock : 互斥鎖就是進程的互相排斥,誰先搶到資源,誰就上鎖改資源內容,為了保證數據的同步性
# 注意:多個鎖一起上,不開鎖,會造成死鎖.上鎖和解鎖是一對.
事件(Event)
# 阻塞事件 :
e = Event()生成事件對象e
e.wait()動態給程式加阻塞 , 程式當中是否加阻塞完全取決於該對象中的is_set() [默認返回值是False]
# 如果是True 不加阻塞
# 如果是False 加阻塞
# 控制這個屬性的值
# set()方法 將這個屬性的值改成True
# clear()方法 將這個屬性的值改成False
# is_set()方法 判斷當前的屬性是否為True (默認上來是False)
進程間通訊 IPC
# IPC Inter-Process Communication
# 實現進程之間通訊的兩種機制:
# 管道 Pipe
# 隊列 Queue
# put() 存放
# get() 獲取
# get_nowait() 拿不到報異常
# put_nowait() 非阻塞版本的put
q.empty() 檢測是否為空 (了解)
q.full() 檢測是否已經存滿 (了解)
–執行緒(Thread)
生產者與消費者模型
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-LYUQwS07-1611230808561)(assets/生產者消費者.png)]