您好,我是碼農飛哥,感謝您閱讀本文,歡迎一鍵三連哦,
本篇開始學習并發編程,本文將重點介紹執行緒的基本概念以及執行緒的生命周期,
干貨滿滿,建議收藏,需要用到時常看看, 小伙伴們如有問題及需要,歡迎踴躍留言哦~ ~ ~,
文章目錄
- 前言
- 行程和執行緒
- 執行緒的創建
- 執行緒的生命周期
- Thread.join()用法詳解,
- sleep函式的用法
- daemon守護執行緒詳解
- 總結
- Python知識圖譜
前言
前面介紹的知識點都是基礎知識點,沒有涉及到并發編程,在實際開始中我們經常需要用到異步并發處理的場景,比如:讀取一個很大的Excel,單個執行緒讀取的話可能很慢,這時候就需要多執行緒并發處理了,
還有就是支付系統,訂單支付成功之后需要異步通知第三方等等場景,
行程和執行緒
行程是什么?行程說白了就是應用程式的執行實體,你在電腦上聽著歌兒,敲著代碼,掛著微信,這些任務都是由不同的應用程式來執行,作業系統會給每個應用程式分配不同的行程,通過CPU的調度來使這些動作可以“同時”進行,這里說是同時進行實際上不是的,因為CPU在同一時間內只能有一條指令執行,但是因為CPU執行的速度太快了,給用戶的感覺就是在同時進行,行程是可以占用物理記憶體的,
執行緒是行程的組成部分,一個行程可以擁有多個執行緒.CPU調度行程的最小粒度是執行緒,其中由主執行緒來完成從開始到結束的全部操作,其他執行緒在主執行緒運行時被創建或者結束,
主執行緒在程式初始化之后就會被創建,如果一個程式只有一個主執行緒就稱為單執行緒,如果有多個執行緒則稱之為多執行緒, 創建多個執行緒之后,每個執行緒的執行都是獨立的,
執行緒的創建
Python創建執行緒的方式有兩種: 創建執行緒都需要引入threading模塊,首先讓我們來看看Thread類的構造方法,
__init__(self, group=None, target=None, name=None,
args=(), kwargs=None, *, daemon=None):
此構造方法中,以上所有引數都是可選引數,即可以使用,也可以忽略,
其中各個引數的含義如下:
- group:指定所創建的執行緒隸屬于哪個執行緒組,
- target:指定所創建的執行緒要呼叫的目標方法,
- args:以元組的方式,為target指定的方法傳遞引數,如果傳入的是元組中有多個引數的話則傳入方式是
(arg1,arg2,....argn,) - kwargs:以字典的方法,為target指定的方法傳遞引數,
- daemon:指定所創建的執行緒是否為后臺執行緒,
- name: 指定執行緒的名稱
- 第一種方式:就是直接呼叫Thread類的構造方法創建一個執行緒的實體,
import threading
# 定義執行緒要呼叫的方法
def async_fun(*add):
for arc in add:
print(threading.current_thread().getName() + " " + arc)
my_tuple = ("碼農飛哥", "好好學習", "早日突破職業瓶頸")
# 創建執行緒
thread = threading.Thread(target=async_fun, args=my_tuple)
# 啟動執行緒
thread.start()
for i in range(4):
print(threading.current_thread().getName() + "執行" + str(i)+ "次")
運行結果是:
Thread-1 碼農飛哥MainThread執行0次
MainThread執行1次
MainThread執行2次
MainThread執行3次
Thread-1 好好學習
Thread-1 早日突破職業瓶頸
如上方法就是實體化一個執行緒Thread-1讓他異步呼叫async_fun方法,可以看出主執行緒MainThread和執行緒Thread-1是交替呼叫的(每次的執行結果都不同),這說明了這兩個執行緒是交替獲得CPU的執行權限的,需要特別注意的是執行緒必須要呼叫start()方法才能執行,
2. 第二種方式:就是繼承threading.Thread,然后,重寫run方法,
import threading
class MyThread(threading.Thread):
def __init__(self, add):
threading.Thread.__init__(self)
self.add = add
# 重寫run()方法
def run(self):
for arc in self.add:
print(threading.current_thread().getName() + " " + arc)
my_tuple = ("碼農飛哥", "好好學習", "早日突破職業瓶頸")
thread = MyThread(my_tuple)
thread.start()
for i in range(4):
print(threading.current_thread().getName() + "執行" + str(i)+ "次")
運行結果是:
Thread-1 碼農飛哥MainThread執行0次
MainThread執行1次
Thread-1 好好學習
Thread-1 早日突破職業瓶頸
MainThread執行2次
MainThread執行3次
這里定義了了MyThread類,并重寫了run方法,run方法就是執行緒真正要執行的任務,相當于上例中async_fun函式的內容移到了run方法中,
執行緒的生命周期
說完了如何創建一個執行緒接下來讓我們來看看執行緒的生命周期,一個執行緒一共有五個狀態,
分別是新建狀態(初始化狀態),就緒狀態,運行狀態,阻塞狀態以及死亡狀態,狀態之間的關系圖如下:

- 新建狀態:執行緒被剛剛創建,且未呼叫start()方法時的狀態,即上面的threading.Thread(target=async_fun, args=my_tuple) 時的執行緒狀態,
- 就緒狀態:呼叫了start()方法之后,執行緒就由新建狀態轉成就緒狀態,就緒狀態就是表示執行緒可以是隨時準備獲取CPU的狀態,
以下幾種情況下執行緒會進入就緒狀態:1.sleep()方法規定的時間已過,2.呼叫了set()方法發出通知,3.其他執行緒釋放了該同步鎖,并由該執行緒獲得, - 運行狀態:當就緒狀態的執行緒獲得了CPU的使用權之后,并開始執行target引數執行的目標函式或者run()方法,就表明執行緒處于運行狀態,
- 阻塞狀態:獲得CPU的調度但是沒有執行完任務的執行緒.
以下幾種情況下:執行緒都會進入阻塞狀態:1.呼叫了sleep()方法,2.呼叫了wait()方法,并且等待條件滿足,3.執行緒試圖獲取某個物件的同步鎖時,如果該鎖被其他執行緒占用,則當前執行緒進入阻塞狀態, - 執行緒死亡狀態:執行緒的任務執行完成或者程式執行程序中發生例外,執行緒都會進入死亡狀態,
Thread.join()用法詳解,
join()方法的功能是在程式指定位置,優先讓該方法的呼叫者使用CPU資源,即呼叫執行緒等待該執行緒完成后,才能繼續用下運行,
該方法的語法格式如下:thread.join( [timeout])
其中,thread為Thread類或其子類的實體化物件;timeout引數作為可選引數,
其功能是指定thread執行緒最多可以霸占CPU資源的時間,如果省略,則默認直到thread執行結束才釋放CPU資源,
import threading
# 定義執行緒要呼叫的方法
def async_fun(*add):
for arc in add:
print(threading.current_thread().getName() + " " + arc)
my_tuple = ("碼農飛哥", "好好學習", "早日突破職業瓶頸")
# 創建執行緒
thread = threading.Thread(target=async_fun, args=my_tuple, name="執行緒1")
thread2 = threading.Thread(target=async_fun, args=my_tuple, name='執行緒2')
# 啟動執行緒
thread.start()
# 等待執行緒1執行完
thread.join()
# 執行緒1執行完之后啟動執行緒2
thread2.start()
thread2.join()
運行結果是:
執行緒1 碼農飛哥
執行緒1 好好學習
執行緒1 早日突破職業瓶頸
執行緒2 碼農飛哥
執行緒2 好好學習
執行緒2 早日突破職業瓶頸
如上有執行緒1和執行緒2兩個執行緒,在執行緒1呼叫thread.join()之后執行緒1和執行緒2的執行由并行改成了串行,也就是說必須是執行緒1執行完之后才啟動執行緒2,現在把該陳述句去掉變成下面這樣:
# 啟動執行緒
thread.start()
# 執行緒1執行完之后啟動執行緒2
thread2.start()
thread2.join()
運行結果是:
執行緒1 碼農飛哥
執行緒2 碼農飛哥
執行緒2 好好學習
執行緒2 早日突破職業瓶頸
執行緒1 好好學習
執行緒1 早日突破職業瓶頸
可以看出執行緒1和執行緒2的運行是并行的,
sleep函式的用法
位于time模塊中的sleep(secs)函式,可以實作令當前執行的執行緒暫停secs秒后在繼續執行,所謂暫停,即令當前執行緒進入阻塞狀態,當達到sleep()函式規定的時間后,
再由阻塞狀態轉為就緒狀態,等待CPU調度,
# 定義執行緒要呼叫的方法
def async_fun(*add):
for arc in add:
start_time = time.time()
time.sleep(2)
print(str((time.time() - start_time)) + " 秒 " + threading.current_thread().getName() + " 結束呼叫" + arc)
my_tuple = ("碼農飛哥", "好好學習", "早日突破職業瓶頸")
# 創建執行緒
thread = threading.Thread(target=async_fun, args=my_tuple)
# 啟動執行緒
thread.start()
運行結果是:
2.0052337646484375 秒 Thread-1 結束呼叫碼農飛哥
2.004210948944092 秒 Thread-1 結束呼叫好好學習
2.002394199371338 秒 Thread-1 結束呼叫早日突破職業瓶頸
可以看出執行緒每次執行都花費了2秒的時間,
daemon守護執行緒詳解
當一個執行緒設定為守護執行緒之后,本次任務執行完成之后執行緒并不會死亡,其生命周期就是主程式的生命周期,也就是說程式不結束,守護執行緒就一直在(執行任務時發生例外的情況除外)
總結
本文是Python并發編程的第一篇,簡單的介紹了執行緒的基本概念以及生命周期,
Python知識圖譜
為了更好幫助更多的小伙伴對Python從入門到精通,我從CSDN官方那邊搞來了一套 《Python全堆疊知識圖譜》,尺寸 870mm x 560mm,展開后有一張辦公桌大小,也可以折疊成一本書的尺寸,有興趣的小伙伴可以了解一下------掃描下圖中的二維碼即可購買,

我本人也已經用上了,感覺非常好用,圖譜桌上放,知識心中留,

我是碼農飛哥,再次感謝您讀完本文,
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/294951.html
標籤:python
上一篇:Python 的圖形用戶界面
