[Language]Python的多線程__Python

來源:互聯網
上載者:User
簡述

多線程設計在系統中是比較關鍵的部分,對於系統效能的提高以及一個較為複雜架構的構建都是很重要的。 進程與線程差別

這部分許多資料可供參考,比如一些動畫介紹,還有CSAPP書中也詳細講到。在嵌入式系統中一般是沒有進程和線程區分概念的,因為嵌入式系統就跑一個程式(一個main入口),通過RTOS管理其中的各個線程(一般稱為task),其實總的就一個進程,可以獨享嵌入式系統的Flash, RAM等資源,也不會有IPC等技術和概念。
在多使用者作業系統,一般非RTOS就是吧,Linux, Windows, Android, MacOS, IOS,上面是會有許許多多的程式可以同時被運行,最後被終止的。一個程式其實就是一段二進位代碼,放在這些電腦的儲存空間上,只有這個程式被載入並執行,此時就有針對這個程式的生命週期和進程概念了,因此其實進程指的是程式的一次執行,進程有其獨立的記憶體、棧、地址空間等,處理序間通訊需要用IPC進行處理序間通訊。 Python中的線程

Python設計之初的考慮是在Python解譯器主迴圈中同時只有一個線程在執行,即Python解譯器可以運行多個線程,但是任意時刻只有一個線程在解譯器中運行。而做到這一點是通過Python的Global Interpreter Lock-GIL來實現的:

Python解譯器使用GIL控制線程執行首先設定GIL,並切換到一個線程去執行然後運行指定數量的位元組碼指令,或者線程主動讓出控制把線程設定為睡眠狀態,並解鎖GIL
Python多線程編程-threading模組

目前需要在Python代碼中使用多線程設計,都是import threading moduel。目前Python的線程沒有優先順序區分,也沒有線程組,線程不可銷毀、停止、掛起、恢複或中斷。 threading module的方法

方法名 詳細說明
threading.active_count() 返回當前處於啟用狀態的Thread對象個數,返回的個數等於threading.enumerate()返回的list的長度
threading.current_thread() 返回當前的Thread對象,相當於調用者的線程
threading.get_ident() 返回當前線程的線程identifier,這是一個非零值
threading.enumerate() 返回當前處於啟用狀態的Thread對象,以list形式返回,包含daemonic線程,dummy線程和main線程
threading.main_thread() 返回main線程對象,一般是Python解譯器開始啟動並執行線程
threading.settrace(func) 為所有從threading module建立的線程設定一個trace函數,該函數會在每個線程的run()方法被調用前,被傳給sys.settrace()
threading.setprofile(func) 為所有從threading module建立的線程設定一個profile函數,該函數會在每個線程的run()方法被調用前,被傳給sys.setprofile()
threading.stack_size([size]) 當建立一個新的線程時返回該線程使用的stack size,size參數可選,用來指定所建立線程的stack size,必須是0或是一個至少為32768的正整數。size未指定會預設使用0值,RuntimeError表示改變stack size不支援,ValueError表示stack size非法值。32K的stack size是目前支援最小的值,足夠的stack空間主要是解譯器本身需要佔用。一般memory是4096 Bytes一個page,Stack size建議設定為4K Bytes的倍數
threading module的常數
常數 詳細說明
threading.TIMEOUT_MAX 阻塞函數(Lock.acquire(), RLock.acquire(), Condition.wait()等)的允許最大的逾時值,如果使用的timeout參數大於這個最大值,就會發生OverflowError
threading module的Thread類(對象)

Thread類是可以單獨控制和啟動並執行線程,可以通過傳遞一個可調用對象給構造器,或者重寫子類的run()方法來指定線程的運作。線程對象被建立,就必須通過start()方法來開始運作,此時會調用其run()方法,線程就啟用了。直到run()方法終止,線程就停止。
其他線程可以調用本線程的join()方法,此時調用本線程join()方法的線程會阻塞,等待本線程執行結束退出,再繼續調用線程的後續執行。
線程也可以標識為daemon線程,在Python程式退出時,daemon線程仍然保留,知道關機時才會退出。
還有一種main線程,即開始運行Python程式的線程,為非daemon線程。
還有dummy線程,這種線程是在threading module之外開啟,比如通過調用的C代碼建立的線程。

類及方法 詳細說明
Thread類 class threading.Thread(group=None,target=None,name=None,args=(),kwargs={},*,daemon=None),類構造器,group表示線程組,目前不支援該功能,用於後續擴充。target是可以被run()方法調用的對象。name是線程名稱。args是參數tuple,用於被target調用。kwargs是關鍵字參數dictionary,用於被target調用。daemon表明線程是否為daemon類別。在Thread子類重寫構造器時,必須首先調用Thread.init()
start() 開始線程的生命週期,該方法會安排run()方法的調用,如果調用start()多次,會發生RuntimeError
run() 線程的生命週期-activity
join(timeout=None) 等待直到線程終止。如果timeout非零,其值為浮點數,要判斷join()是否逾時,需要使用is_alive()方法看,如果在調用了join()方法後再調用同一線程的is_alive()方法,如果還是alive的,說明join()逾時了。如果timeout為None,則調用者會一直阻塞直到被調用join()方法的線程終止。一個線程的join()可被多次調用
name
getName()
setName()
ident 線程idnetifier
is_alive() 判斷線程是否alive,主要是看run()是否結束
daemon daemon線程標誌
isDaemon 判斷是否daemon線程
setDaemon 設定為daemon線程

threading module的Lock類(對象)

Lock即primitive lock,原始鎖,只會處於兩個狀態中的一個,“locked”(初始態)或“unlocked”。並有acquire()和release()兩個方法。acquire()有阻塞和非阻塞兩種方式,阻塞是會一直等待直到鎖釋放,而非阻塞是如果擷取不到鎖就立即返回false。相關圖示如下:
threading module的RLock類(對象)

Reentrant Lock,可重新進入鎖,即對於同一線程而言,是可重新進入鎖,而對於其他線程而言,和上面的Lock沒有區別。
和Lock的區別在於:在某一線程acquire()一個lock時,發現lock已經被本線程之前acquire()過但還未release(),此時可以繼續acquire(),只是要進行同樣次數的release()後才會將lock最終unlocked。
所以可重新進入鎖就是基於Lock增加了lock的owner機制,lock的owner是自身,可以繼續acquire(),並將計數器加一。 threading module的Condition類(對象)

Condition Variable-條件變數,和Lock總是有著關聯,底層機制應當還是使用Lock來實現的,Condition Variable的一個很好的應用情境就是“生產者-消費者”模型:

# Consume an itemwith cv:    cv.wait_for(an_item_is_available)    get_an_available_item()# Produce one itemwith cv:    make_an_item_available()    cv.notify()
類與方法 詳細說明
threading.Condition class threading.Condition(lock=None),用於實現條件變數對象,允許多個線程wait一個條件變數,直到被一個線程notify。如果lock參數非None,必須是從外部傳入的Lock或RLock。如果lock參數是None,會建立一個RLock
acquire(*args) acquire上面提到的傳入的或建立的lock
release() release上面提到的傳入的或建立的lock
wait(timeout=None) 等待notify或到timeout發生,其實就是相當於acquire()一個lock,然後等待有人將其release()
wait_for(predicate, timeout=None) 等待直到condition為True,predicate是可調用的且其結果是boolean值
notify(n=1) 預設喚醒一個等待condition的線程。這個方法可以喚醒最多n個等待condition的線程
notify_all() 喚醒所有等待condition的線程

condition機制如下圖所示:

即Consumer等待條件滿足,而Producer則觸發條件滿足,這樣來做線程間的同步和通訊。 threading module的Semaphore類(對象)

Semaphore內部維護一個計數器,每次acquire()計數器減一,每次release()計數器加一,計數器不能為負數。 threading module的Event類(對象)

線程通訊最為簡單的機制,一個線程拋出一個訊號,另外線程等待這個訊號。

類與方法 詳細說明
Event class threading.Event。管理一個內部flag(True or False)
is_set() 判斷內部flag是否True
set() 將內部flag設定為True
clear() 將內部flag設定為False
wait(timeout=None) 阻塞直到內部flag為True,或者timeout時間到

threading module的Timer類(對象)

Timer用於某個動作需要等待一定時間後才開始執行。Timer是Thread的子類,除了start()方法,Timer還有cancel()方法來停止timer。
程式碼範例:

def hello():    print("hello, world")t = Timer(30.0, hello)t.start() # after 30 seconds, "hello, world" will be printed
類與方法 詳細說明
Timer class threading.Timer(interval, function, args=None, kwargs=None)。timer將在interval的時間後運行function函數,args是function函數的參數,kwargs是function函數的關鍵字參數
cancel() 停止timer,取消timer後續函數的執行(僅在等待狀態有用)
threading module的Barrier類(對象)

Barrier類用於多個線程間互相等待的情境,每個線程通過調用wait()嘗試傳輸barrier,並會block直到所有線程都傳輸了barrier。線程最終會同步release。
舉例:

b = Barrier(2, timeout=5)def server():    start_server()    b.wait()    while True:        connection = accept_connection()        process_server_connection(connection)def client():    b.wait()    while True:        connection = make_connection()        process_client_connection(connection)
類和方法 詳細說明
Barrier class threading.Barrier(parties, action=None, timeout=None)。parties是線程數目,action是線上程release時可調用的,timeout是沒有任何線程調用wait()的逾時時間
wait(timeout=None) Pass the barrier,傳回值是0到parties-1的值
reset() 將Barrier恢複為預設狀態-空
abort() 將Barrier設定為broken狀態
parties 需要pass barrier的線程個數
n_waiting 當前等待barrier的線程個數
broken 布爾值,表明barrier是否broken
Python多線程編程-queue模組

queue是同步的隊列類,multi-producer, multi-consumer隊列,主要用於threading編程中,多線程之間的安全通訊。queue實現了所有需要的鎖語義。且實現了3類queue:

queue類別 詳細說明
FIFO 先進先出,一般queue
LIFO 後進先出,像stack
Priority queue 入口進行了分類,最低的入口最先出
queue module的類和異常
類或異常 詳細說明
Queue class queue.Queue(maxsize=0),FIFO queue構造,maxsize是queue最大空間,如果queue滿,入隊就會block直到有出隊發生
LifoQueue class queue.LifoQueue(maxsize=0),LIFO queue構造,maxsize是queue最大空間,如果queue滿,入隊就會block直到有出隊發生
PriorityQueue class queue.PriorityQueue(maxsize=0),Priority queue構造,maxsize是queue最大空間,如果queue滿,入隊就會block直到有出隊發生
Empty exception queue.Empty,隊空
Full exception queue.Full,隊滿
queue module的Queue類(對象)
方法 詳細描述
Queue.qsize() 返回queue中大約的元素個數
Queue.empty() 判斷queue是否空
Queue.full() 判斷queue是否滿
Queue.put(item, block=True, timeout=None) 入隊
Queue.put_nowait(item) 和put(item,False)一樣
Queue.get(block=True, timeout=None) 出隊
Queue.get_nowait() 和get(False)一樣

另外還有兩個方法,用於支援入隊的任務是否被daemon消費者線程處理的跟蹤:
Queue.task_done()和Queue.join()。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.