微吼云上線多路互動直播服務(wù) 加速多場景互動直播落地
617
2025-04-01
一. 線程的使用
1. 導(dǎo)入線程模塊
#導(dǎo)入線程模塊 import threading
1
2
2. 線程類Thread參數(shù)說明
Thread([group [, target [, name [, args [, kwargs]]]]])
group: 線程組,目前只能使用None
target: 執(zhí)行的目標(biāo)任務(wù)名
args: 以元組的方式給執(zhí)行任務(wù)傳參
kwargs: 以字典方式給執(zhí)行任務(wù)傳參
name: 線程名,一般不用設(shè)置
3. 啟動線程
啟動線程使用start方法
4. 多線程完成多任務(wù)的代碼
import threading import time # 唱歌任務(wù) def sing(): # 擴(kuò)展: 獲取當(dāng)前線程 # print("sing當(dāng)前執(zhí)行的線程為:", threading.current_thread()) for i in range(3): print("正在唱歌...%d" % i) time.sleep(1) # 跳舞任務(wù) def dance(): # 擴(kuò)展: 獲取當(dāng)前線程 # print("dance當(dāng)前執(zhí)行的線程為:", threading.current_thread()) for i in range(3): print("正在跳舞...%d" % i) time.sleep(1) if __name__ == '__main__': # 擴(kuò)展: 獲取當(dāng)前線程 # print("當(dāng)前執(zhí)行的線程為:", threading.current_thread()) # 創(chuàng)建唱歌的線程 # target: 線程執(zhí)行的函數(shù)名 sing_thread = threading.Thread(target=sing) # 創(chuàng)建跳舞的線程 dance_thread = threading.Thread(target=dance) # 開啟線程 sing_thread.start() dance_thread.start()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
5. 小結(jié)
導(dǎo)入線程模塊
import threading
1
創(chuàng)建子線程并指定執(zhí)行的任務(wù)
sub_thread = threading.Thread(target=任務(wù)名)
1
啟動線程執(zhí)行任務(wù)
sub_thread.start()
1
二. 線程執(zhí)行帶有參數(shù)的任務(wù)
1. 線程執(zhí)行帶有參數(shù)的任務(wù)的介紹
前面我們使用線程執(zhí)行的任務(wù)是沒有參數(shù)的,假如我們使用線程執(zhí)行的任務(wù)帶有參數(shù),如何給函數(shù)傳參呢?
Thread類執(zhí)行任務(wù)并給任務(wù)傳參數(shù)有兩種方式:
args 表示以元組的方式給執(zhí)行任務(wù)傳參
kwargs 表示以字典方式給執(zhí)行任務(wù)傳參
2. args參數(shù)的使用
示例代碼:
import threading import time # 帶有參數(shù)的任務(wù) def task(count): for i in range(count): print("任務(wù)執(zhí)行中..") time.sleep(0.2) else: print("任務(wù)執(zhí)行完成") if __name__ == '__main__': # 創(chuàng)建子線程 # args: 以元組的方式給任務(wù)傳入?yún)?shù) sub_thread = threading.Thread(target=task, args=(5,)) sub_thread.start()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
3. kwargs參數(shù)的使用
示例代碼:
mport threading import time # 帶有參數(shù)的任務(wù) def task(count): for i in range(count): print("任務(wù)執(zhí)行中..") time.sleep(0.2) else: print("任務(wù)執(zhí)行完成") if __name__ == '__main__': # 創(chuàng)建子線程 # kwargs: 表示以字典方式傳入?yún)?shù) sub_thread = threading.Thread(target=task, kwargs={"count": 3}) sub_thread.start()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
4. 小結(jié)
線程執(zhí)行任務(wù)并傳參有兩種方式:
元組方式傳參(args) :元組方式傳參一定要和參數(shù)的順序保持一致。
字典方式傳參(kwargs):字典方式傳參字典中的key一定要和參數(shù)名保持一致。
四. 線程使用的相關(guān)注意點(diǎn)
1. 線程的注意點(diǎn)介紹
線程之間執(zhí)行是無序的
主線程會等待所有的子線程執(zhí)行結(jié)束再結(jié)束
線程之間共享全局變量
線程之間共享全局變量數(shù)據(jù)出現(xiàn)錯誤問題
2. 線程之間執(zhí)行是無序的
import threading import time def task(): time.sleep(1) print("當(dāng)前線程:", threading.current_thread().name) if __name__ == '__main__': for _ in range(5): sub_thread = threading.Thread(target=task) sub_thread.start()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
說明:
線程之間執(zhí)行是無序的,它是由cpu調(diào)度決定的 ,cpu調(diào)度哪個線程,哪個線程就先執(zhí)行,沒有調(diào)度的線程不能執(zhí)行。
進(jìn)程之間執(zhí)行也是無序的,它是由操作系統(tǒng)調(diào)度決定的,操作系統(tǒng)調(diào)度哪個進(jìn)程,哪個進(jìn)程就先執(zhí)行,沒有調(diào)度的進(jìn)程不能執(zhí)行。
3. 主線程會等待所有的子線程執(zhí)行結(jié)束再結(jié)束
假如我們現(xiàn)在創(chuàng)建一個子線程,這個子線程執(zhí)行完大概需要2.5秒鐘,現(xiàn)在讓主線程執(zhí)行1秒鐘就退出程序,查看一下執(zhí)行結(jié)果,示例代碼如下:
import threading import time # 測試主線程是否會等待子線程執(zhí)行完成以后程序再退出 def show_info(): for i in range(5): print("test:", i) time.sleep(0.5) if __name__ == '__main__': sub_thread = threading.Thread(target=show_info) sub_thread.start() # 主線程延時1秒 time.sleep(1) print("over")
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
設(shè)置守護(hù)主線程的示例代碼:
import threading import time # 測試主線程是否會等待子線程執(zhí)行完成以后程序再退出 def show_info(): for i in range(5): print("test:", i) time.sleep(0.5) if __name__ == '__main__': # 創(chuàng)建子線程守護(hù)主線程 # daemon=True 守護(hù)主線程 # 守護(hù)主線程方式1 sub_thread = threading.Thread(target=show_info, daemon=True) # 設(shè)置成為守護(hù)主線程,主線程退出后子線程直接銷毀不再執(zhí)行子線程的代碼 # 守護(hù)主線程方式2 # sub_thread.setDaemon(True) sub_thread.start() # 主線程延時1秒 time.sleep(1) print("over")
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
3. 線程之間共享全局變量
需求:
定義一個列表類型的全局變量
創(chuàng)建兩個子線程分別執(zhí)行向全局變量添加數(shù)據(jù)的任務(wù)和向全局變量讀取數(shù)據(jù)的任務(wù)
查看線程之間是否共享全局變量數(shù)據(jù)
import threading import time # 定義全局變量 my_list = list() # 寫入數(shù)據(jù)任務(wù) def write_data(): for i in range(5): my_list.append(i) time.sleep(0.1) print("write_data:", my_list) # 讀取數(shù)據(jù)任務(wù) def read_data(): print("read_data:", my_list) if __name__ == '__main__': # 創(chuàng)建寫入數(shù)據(jù)的線程 write_thread = threading.Thread(target=write_data) # 創(chuàng)建讀取數(shù)據(jù)的線程 read_thread = threading.Thread(target=read_data) write_thread.start() # 延時 # time.sleep(1) # 主線程等待寫入線程執(zhí)行完成以后代碼在繼續(xù)往下執(zhí)行 write_thread.join() print("開始讀取數(shù)據(jù)啦") read_thread.start()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
4. 線程之間共享全局變量數(shù)據(jù)出現(xiàn)錯誤問題
需求:
定義兩個函數(shù),實(shí)現(xiàn)循環(huán)100萬次,每循環(huán)一次給全局變量加1
創(chuàng)建兩個子線程執(zhí)行對應(yīng)的兩個函數(shù),查看計算后的結(jié)果
import threading # 定義全局變量 g_num = 0 # 循環(huán)一次給全局變量加1 def sum_num1(): for i in range(1000000): global g_num g_num += 1 print("sum1:", g_num) # 循環(huán)一次給全局變量加1 def sum_num2(): for i in range(1000000): global g_num g_num += 1 print("sum2:", g_num) if __name__ == '__main__': # 創(chuàng)建兩個線程 first_thread = threading.Thread(target=sum_num1) second_thread = threading.Thread(target=sum_num2) # 啟動線程 first_thread.start() # 啟動線程 second_thread.start()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
注意點(diǎn):
多線程同時對全局變量操作數(shù)據(jù)發(fā)生了錯誤
錯誤分析:
兩個線程first_thread和second_thread都要對全局變量g_num(默認(rèn)是0)進(jìn)行加1運(yùn)算,但是由于是多線程同時操作,有可能出現(xiàn)下面情況:
在g_num=0時,first_thread取得g_num=0。此時系統(tǒng)把first_thread調(diào)度為”sleeping”狀態(tài),把second_thread轉(zhuǎn)換為”running”狀態(tài),t2也獲得g_num=0
然后second_thread對得到的值進(jìn)行加1并賦給g_num,使得g_num=1
然后系統(tǒng)又把second_thread調(diào)度為”sleeping”,把first_thread轉(zhuǎn)為”running”。線程t1又把它之前得到的0加1后賦值給g_num。
這樣導(dǎo)致雖然first_thread和first_thread都對g_num加1,但結(jié)果仍然是g_num=1
全局變量數(shù)據(jù)錯誤的解決辦法:
線程同步: 保證同一時刻只能有一個線程去操作全局變量 同步: 就是協(xié)同步調(diào),按預(yù)定的先后次序進(jìn)行運(yùn)行。如:你說完,我再說, 好比現(xiàn)實(shí)生活中的對講機(jī)
線程同步的方式:
線程等待(join)
互斥鎖
線程等待的示例代碼:
import threading # 定義全局變量 g_num = 0 # 循環(huán)1000000次每次給全局變量加1 def sum_num1(): for i in range(1000000): global g_num g_num += 1 print("sum1:", g_num) # 循環(huán)1000000次每次給全局變量加1 def sum_num2(): for i in range(1000000): global g_num g_num += 1 print("sum2:", g_num) if __name__ == '__main__': # 創(chuàng)建兩個線程 first_thread = threading.Thread(target=sum_num1) second_thread = threading.Thread(target=sum_num2) # 啟動線程 first_thread.start() # 主線程等待第一個線程執(zhí)行完成以后代碼再繼續(xù)執(zhí)行,讓其執(zhí)行第二個線程 # 線程同步: 一個任務(wù)執(zhí)行完成以后另外一個任務(wù)才能執(zhí)行,同一個時刻只有一個任務(wù)在執(zhí)行 first_thread.join() # 啟動線程 second_thread.start()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
5. 小結(jié)
線程執(zhí)行執(zhí)行是無序的
主線程默認(rèn)會等待所有子線程執(zhí)行結(jié)束再結(jié)束,設(shè)置守護(hù)主線程的目的是主線程退出子線程銷毀。
線程之間共享全局變量,好處是可以對全局變量的數(shù)據(jù)進(jìn)行共享。
線程之間共享全局變量可能會導(dǎo)致數(shù)據(jù)出現(xiàn)錯誤問題,可以使用線程同步方式來解決這個問題。
Python 任務(wù)調(diào)度
版權(quán)聲明:本文內(nèi)容由網(wǎng)絡(luò)用戶投稿,版權(quán)歸原作者所有,本站不擁有其著作權(quán),亦不承擔(dān)相應(yīng)法律責(zé)任。如果您發(fā)現(xiàn)本站中有涉嫌抄襲或描述失實(shí)的內(nèi)容,請聯(lián)系我們jiasou666@gmail.com 處理,核實(shí)后本網(wǎng)站將在24小時內(nèi)刪除侵權(quán)內(nèi)容。
版權(quán)聲明:本文內(nèi)容由網(wǎng)絡(luò)用戶投稿,版權(quán)歸原作者所有,本站不擁有其著作權(quán),亦不承擔(dān)相應(yīng)法律責(zé)任。如果您發(fā)現(xiàn)本站中有涉嫌抄襲或描述失實(shí)的內(nèi)容,請聯(lián)系我們jiasou666@gmail.com 處理,核實(shí)后本網(wǎng)站將在24小時內(nèi)刪除侵權(quán)內(nèi)容。