python併發程式設計之執行緒
阿新 • • 發佈:2021-07-22
1、為什麼要有執行緒
因為程序雖然有其優點,但也有缺點:
1.程序只能在一個時間幹一件事,如果想同時幹兩件事或多件事,程序就無能為力了。
2.程序在執行的過程中如果阻塞,例如等待輸入,整個程序就會掛起,即使程序中有些工作不依賴於輸入的資料,也將無法執行。
2、執行緒的出現
正因為程序的缺點,所以需要解決它。在80年代,出現了能獨立執行的基本單位——執行緒(Threads)
注意:程序是資源分配的最小單位,執行緒是CPU排程的最小單位。每一個程序中至少有一個執行緒。
3、程序和執行緒的區別
可以歸納為以下4點: 1.地址空間和其它資源(如開啟檔案):程序間相互獨立,同一程序的各執行緒間共享。某程序內的執行緒在其它程序不可見。 2.通訊:程序間通訊IPC,執行緒間可以直接讀寫程序資料段(如全域性變數)來進行通訊——需要程序同步和互斥手段的輔助,以保證資料的一致性。 3.排程和切換:執行緒上下文切換比程序上下文切換要快得多。 4.在多執行緒作業系統中,程序不是一個可執行的實體。
4、執行緒的特點
1.輕型實體 執行緒中的實體基本上不擁有系統資源,只是有一點必不可少的、能保證獨立執行的資源。 執行緒的實體包括程式、資料和TCB。執行緒是動態概念,它的動態特性由執行緒控制塊TCB(Thread Control Block)描述, TCB用於指示被執行指令序列的程式計數器、保留區域性變數、少數狀態引數和返回地址等的一組暫存器和堆疊。 TCB包括以下資訊: 1.執行緒狀態。 2.當執行緒不執行時,被儲存的現場資源。 3.一組執行堆疊。 4.存放每個執行緒的區域性變數主存區。 5.訪問同一個程序中的主存和其它資源。 2.獨立排程和分派的基本單位 在多執行緒OS中,執行緒是能獨立執行的基本單位,因而也是獨立排程和分派的基本單位。 由於執行緒很“輕”,故執行緒的切換非常迅速且開銷小(在同一程序中的)。 3.共享程序資源 執行緒在同一程序中的各個執行緒,都可以共享該程序所擁有的資源,由於同一個程序內的執行緒共享記憶體和檔案,所以執行緒之間互相通訊不必呼叫核心。 4.可併發執行 在一個程序中的多個執行緒之間,可以併發執行,甚至允許在一個程序中所有執行緒都能併發執行; 同樣,不同程序中的執行緒也能併發執行,充分利用和發揮了處理機與外圍裝置並行工作的能力。
5、如何開啟執行緒
方法一: from multiprocessing import Process from threading import Thread def task(): print("我是子執行緒") if __name__ == '__main__': t = Thread(target=task, args=()) t.start() print("主執行緒") 方法二:重寫run方法 from threading import Thread import time class Sayhi(Thread): def __init__(self,name): super().__init__() self.name=name def run(self): time.sleep(2) print('%s say hello' % self.name) if __name__ == '__main__': t = Sayhi('nick') t.start() print('主執行緒')
6、GIL全域性直譯器鎖
1. Python在設計之初就考慮到要在主迴圈中,同時只有一個執行緒在執行
2. Python 直譯器中可以“執行”多個執行緒,但在任意時刻只有一個執行緒在直譯器中執行。
為了實現上述,就有了GIL全域性直譯器鎖
1、GIL鎖它是在python直譯器中的, 只在cpython中有, pypy直譯器是沒有GIL鎖的,
2、起一個垃圾回收執行緒, 一個是正常執行的執行緒
3、設定了一把鎖(GIL鎖), 一個執行緒要想執行,必須拿到這把鎖
4、同一時刻,開啟一個程序,一個程序中可以有多個執行緒, 只能有一個執行緒在執行
5、如果是計算密集型:要開程序
6、如果是io密集型:要開執行緒
7、執行緒間資料是共享的
import os
from threading import Thread
def work():
global n
n=0
if __name__ =='__main__':
n = 1
t = Thread(target=work,)
t.start()
t.join()
print('主',n) # 檢視結果為0,因為同一程序內的執行緒之間共享程序內的資料
8、守護程序
from threading import Thread
import time
def task():
time.sleep(1)
print("我是子執行緒")
if __name__ == '__main__':
t = Thread(target=task,)
t.setDaemon(True) # 開啟守護執行緒, 主執行緒結束,子執行緒跟著結束
t.start()
print("主執行緒")
9、Thread類的方法
Thread例項物件的方法:
isAlive():返回執行緒是否活動的。
getName():返回執行緒名。
setName():設定執行緒名。
join():先執行完子執行緒,再執行做主執行緒
threading模組提供的一些方法:
threading.currentThread():返回當前的執行緒變數。
threading.enumerate():返回一個包含正在執行的執行緒的list。正在執行指執行緒啟動後、結束前,不包括啟動前和終止後的執行緒。
threading.activeCount():返回正在執行的執行緒數量,與len(threading.enumerate())有相同的結果。