19 - 線程📄目錄1 多任務2 多線程2.1 線程和進程2.2 多線程2.3 多線程的特點2.4 線程之間共享資源2.5 資源競爭3 線程同步3.1 線程等待john()4 互斥鎖4.1 總結導航連結:
以下看似一起執行,實則有先後次序

xxxxxxxxxximport timedef sing(): print("I am singing") time.sleep(2) # 睡眠,以秒為單位def dance(): print("I am dancing") time.sleep(2) print("End!")sing()dance()輸出結果:
xxxxxxxxxxI am singingI am dancingEnd!進程:是操作系統進行資源分配的基本單位,每打開一個程序至少就會有一個進程
線程:是CPU調度的基本單位,每一個進程至少都會有一個線程,這個線程通常就是我們所說的主線程
💡 一個進程默認有一個線程,進程裡面可以創建多個線程
💡 線程是依附在進程裡面的,沒有進程就沒有線程
運行時要先導入線程模塊import threading
Thread線程類參數:
target:執行的任務名(要運行的函數不用添加小括號)
args:以元組的形式給任務傳參
kwargs:以字典的形式給任務傳參

xxxxxxxxxximport threading # 平常應該放到文件開始位置import timedef sing(name): print(f'{name} is singing!') time.sleep(2) print('He/She is done!')def hike(name): print(f'{name} is hiking!') time.sleep(2) print('He/She is back!')# 主程序入口if __name__ == '__main__': # 1. 創建子線程 # thread1 = threading.Thread(target=sing) # 不用傳參的例子 thread1 = threading.Thread(target=sing, args=('Victoria',)) # print(thread1) # 打印結果<Thread(Thread-1 (sing), initial)>,代表這是線程對象 thread2 = threading.Thread(target=hike, args=('Antonio',)) # 3. 守護線程,必須放在start()前面。主線程執行結束,子線程也會跟着結束。 thread1.daemon = True # 3.12版本及以後適用,以前是thread1.setDaeman(True) thread2.daemon = True # ChatGPT稱thread2.Daemon = True(D大寫)是錯誤,應用小寫 # 2. 開啟子線程 thread1.start() thread2.start() # 4. 阻塞主線程join():暫停的作用,等子線程執行結束後,主線程才會繼續執行,必須放在start()後面 thread1.join() thread2.join() # 6. (可選)更改線程名 thread1.name = '子線程1' thread2.name = '子線程2' # 5. (可選)獲取線程名字 print(thread1.name, thread2.name) # 3.12版本及以後適用,以前是print(thread1.getName()) print('Main thread done!')輸出結果:
xxxxxxxxxxVictoria is singing!Antonio is hiking!He/She is back!He/She is done!子線程1 子線程2Main thread done!💡 主程序入口下要做的事情:
創建子線程
開啟子線程
守護線程,必須放在start()前面。主線程執行結束,子線程也會跟着結束
阻塞主線程join():暫停的作用,等子線程執行結束後,主線程才會繼續執行,必須放在start()後面
(可選)獲取線程名字
(可選)更改線程名
線程之間執行是無序的
線程執行是根據CPU調度決定的,先調度哪個就執行哪個

xxxxxxxxxximport threadingimport timedef task(): time.sleep(1) print('當前線程是:', threading.current_thread().name) # 顯示當前線程對象名if __name__ == '__main__': for i in range(5): # 每循環一次就創建一個子線程 thread = threading.Thread(target=task) # 啟動子線程 thread.start()輸出結果(每次輸出結果都不一樣,混亂是因為資源競爭):
xxxxxxxxxx當前線程是:當前線程是: Thread-2 (task)當前線程是:當前線程是: Thread-5 (task)當前線程是: Thread-4 (task) Thread-1 (task)Thread-3 (task)
xxxxxxxxxximport threadingimport timew = 10li = [] # 定義全局變量# 寫入數據def wdata(n): for i in range(n): li.append(i) time.sleep(1) print("寫入的數據是:", li)def rdata(): print("讀取的數據是:", li)if __name__ == "__main__": # 創建子線程 wd = threading.Thread(target=wdata, args=(w,)) rd = threading.Thread(target=rdata, args=()) # 開啟子線程 wd.start() wd.join() # 阻塞主線程,在這裡就是讓rd.start()在wd線程完成後才能執行 rd.start() rd.join()輸出結果:
xxxxxxxxxx寫入的數據是: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]讀取的數據是: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
xxxxxxxxxxa = 0b = 1000000def add(): global a for i in range(b): global a a += 1 print('第一次累加:',a)def add2(): global a for i in range(b): global a a += 1 print('第二次累加:',a)if __name__ == '__main__': a1 = threading.Thread(target=add) a2 = threading.Thread(target=add2) a1.start() a2.start()輸出結果(第一次累加每次輸出結果都不一樣,混亂是因為資源競爭):
xxxxxxxxxx第一次累加: 1697532第二次累加: 2000000主線程和創建的子線程之間各自執行完自己的代碼直至結束
john()
xxxxxxxxxxa = 0b = 1000000def add(): global a for i in range(b): global a a += 1 print('第一次累加:',a)def add2(): global a for i in range(b): global a a += 1 print('第二次累加:',a)if __name__ == '__main__': a1 = threading.Thread(target=add) a2 = threading.Thread(target=add2) a1.start() a1.join() # 等待a1子線程執行結束之後,代碼才繼續往下運行 a2.start() a2.join()輸出結果:
xxxxxxxxxx第一次累加: 1000000第二次累加: 2000000概念:對共享數據進行鎖定,保證多個線程訪問共享數據不會出現數據錯誤問題:保證同一時刻只能有一個線程去操作
方法:
acquire():上鎖
release():釋放鎖
⚠️⚠️注意:這兩個方法必須成對出現,否則會形成死鎖

xxxxxxxxxxfrom threading import Lock# 1. 創建全局互斥鎖lock = Lock()a = 0b = 1000000def add(): # 2. 上鎖 lock.acquire() global a for i in range(b): global a a += 1 print('第一次累加:',a) # 3. 釋放鎖 lock.release()def add2(): lock.acquire() global a for i in range(b): global a a += 1 print('第二次累加:',a) lock.release()if __name__ == '__main__': a1 = threading.Thread(target=add) a2 = threading.Thread(target=add2) a1.start() a2.start()輸出結果:
xxxxxxxxxx第一次累加: 1000000第二次累加: 2000000互斥鎖也是線程同步的一種
互斥鎖的作用:保證同一個時刻只有一個線程去操作共享數據,保證共享數據不會出現錯誤問題
⚠️⚠️上鎖和釋放鎖必須成對出現,否則容易造成「死鎖」現象
⚠️⚠️死鎖:一直等待對方釋放鎖的情況。會造成應用程序停止響應,不能再處理其他任務
❗互斥鎖的缺點:會影響代碼的執行效率
| 目的地 | 超連結 |
|---|---|
| 首頁 | 返回主頁 |
| Python學習 | Python學習 |
| 上一篇 | 18 - 迭代器&生成器 |
| 下一篇 | 20 - 進程 |