Python 基于線程的并行 threading模塊的用法
threading模塊是基于_thread模塊的高級線程接口,相比于低層的_thread模塊,它提供了代表線程的對象和同步化工具,在threading模塊中,只要任何一個派生線程(守護線程除外)在運行中,程序都不會退出,不再需要像_thread那樣控制主線程等待。
一、threading模塊基本用法
threading模塊基于_thread進行了類封裝,其用于構(gòu)造線程的類為threading.Thread,通過創(chuàng)建類實例的方式來創(chuàng)建線程對象。
1.1 threading.Thread類
threading.Thread類的主要參數(shù)如下:
class threading.Thread(target=None, name=None, args=(), kwargs={}, *, daemon=None)
參數(shù)解釋:
- target,用于定義子線程的活動,這應該是個可調(diào)用的函數(shù)。
- name,線程的名稱。
- args,可調(diào)用函數(shù)的參數(shù)。
- kwargs,可調(diào)用函數(shù)的關鍵字參數(shù)。
- daemon,是否將線程設置為守護線程。
通過調(diào)用threading.Thread類創(chuàng)建出來的實例即是線程對象,線程對象創(chuàng)建后,需要調(diào)用.start方法啟動,這個方法會在獨立的線程中喚起run方法,因此有2種方法可以定義子線程的活動:
- 向構(gòu)造類threading.Thread傳遞一個可調(diào)用對象(target參數(shù))。
- 通過子類重載run方法。
下面通過案例演示2種用法。
1.2 用法1:通過threading.Thread定義子線程活動
下面代碼先定義一個函數(shù)func,隨后調(diào)用threading.Thread創(chuàng)建2個線程對象,調(diào)用時通過target=func傳遞自定義函數(shù)(線程活動),最后通過線程對象的.start方法啟動線程:
import threading def func(id): print('我是 {} 號子線程'.format(id)) t1 = threading.Thread(target=func, args=(1,)) t2 = threading.Thread(target=func, args=(2,)) t1.start() t2.start()
1.3 用法2:通過子類重載run方法定義子線程活動
還是上面的例子,這次通過重載子類的run方法來定義子線程活動,當調(diào)用線程對象的.start方法啟動子線程時,子線程會自動調(diào)用.run方法。
import threading def func(id): print('我是 {} 號子線程'.format(id)) # 創(chuàng)建子類MyThread, threading.Thread為其超類 class MyThread(threading.Thread): def __init__(self, id): self.id = id threading.Thread.__init__(self) # 重載run方法 def run(self): print('我是 {} 號子線程'.format(self.id)) t1 = MyThread(1) t2 = MyThread(2) # 啟動子線程,會調(diào)用子類中的run方法 t1.start() t2.start()
二、threading模塊其他方法
threading模塊相對_thread模塊額外提供了一些線程狀態(tài)查詢和控制工具,下面介紹幾個主要方法。
2.1 共享訪問控制 - threading.Lock
多線程必然會涉及到共享資源的訪問,threading模塊提供了一個.Lock方法(和_thread.allocate_lock是同一個東西)用于創(chuàng)建鎖對象,通過鎖來控制共享資源的訪問,基于上面的類MyThread同時創(chuàng)建10個子線程:
for i in range(10): MyThread(i).start()
可以看到上面的輸出出現(xiàn)了重疊,這是因為這10個子線程共享一個標準輸出流,可能出現(xiàn)同時打印的情況。下面把MyThread類改造一下,通過.Lock對象來同步子線程的打印操作(每次打印前先獲取鎖,防止出現(xiàn)2個子線程同時打?。?/p>
class MyThread(threading.Thread): # 新增一個參數(shù)mutex,用于傳入鎖 def __init__(self, id, mutex): self.id = id self.mutex = mutex threading.Thread.__init__(self) # 重載run方法 def run(self): # 通過with語句管理鎖,打印前先獲取鎖,打印完成釋放 with self.mutex: print('我是 {} 號子線程'.format(self.id)) # 創(chuàng)建一個鎖對象 mutex = threading.Lock() for i in range(10): # 每個子線程啟動時都傳入該鎖 MyThread(i, mutex).start()
- mutex = threading.Lock() 創(chuàng)建了一個鎖對象,并在創(chuàng)建子線程時傳入(這10個子線程傳入的是同一把鎖)。
- 子類的run方法,在執(zhí)行print語句前新增了with self.mutex,這會嘗試獲取鎖,如果當前鎖被其他子線程占用(正在打印),那么它會等待。
- 鎖對象也可以通過.acuqure和.release方法手動獲取和釋放,但建議還是使用with來管理(方便)。
2.2 阻塞方法 - threading.Thread.join
每個線程對象都有一個join方法,這個方法會阻塞調(diào)用者,直到線程終結(jié),這對于主線程來說是一個信號,通過join方法可以用來監(jiān)控子線程的完成情況,適合執(zhí)行在子線程完成后再執(zhí)行的動作。
下面改造一下子類的run方法,讓每個線程打印前隨機等待1-5秒,然后調(diào)用Thread.join方法,這個方法會阻塞主線程(等待子線程完成),當所有子線程執(zhí)行完畢時(.join方法返回),立刻打印"所有子線程執(zhí)行完畢"。
下面代碼在run方法的print之前加入了time.sleep(random.randint(1,5))讓子線程隨機睡眠1-5秒,因此子線程的結(jié)束時間是不確定的:
import time, random class MyThread(threading.Thread): # 新增一個參數(shù)mutex,用于傳入鎖 def __init__(self, id): self.id = id threading.Thread.__init__(self) # 重載run方法 def run(self): # 打印之前隨機睡眠1-5秒 time.sleep(random.randint(1,5)) print('我是 {} 號子線程'.format(self.id)) threads = [] for i in range(10): # 每個子線程啟動時都傳入該鎖 ti = MyThread(i) threads.append(ti) ti.start() print("開始等待子線程執(zhí)行...") for thread in threads: # 針對每個子線程都會調(diào)用.join方法,所有子線程結(jié)束后,才會繼續(xù)向下執(zhí)行 thread.join() print("所有子線程執(zhí)行完畢...")
可以看到通過Thread.join方法阻塞主線程,可以保證在所有子線程都執(zhí)行完畢后,才打印"所有子線程執(zhí)行完畢…"。
以上即是threading模塊的基本用法,子線程還有.is_alive方法用來檢測是否存活,另外還有遞歸鎖可以用來嵌套獲取鎖,有興趣的同學可以深入研究一下。
最后:由于Cpython的中存在"全局解釋器鎖(GIL)",這個會限制利用多核CPU的計算資源(Python4.0可能會修復),因此多線程比較適合I/O密集型任務,對于CPU密集型任務,推薦還是使用多進程并發(fā)(multiprocessing模塊)。
到此這篇關于Python 基于線程的并行 threading模塊的用法的文章就介紹到這了,更多相關Python 線程并行threading用法內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
Python OpenCV 調(diào)用攝像頭并截圖保存功能的實現(xiàn)代碼
這篇文章主要介紹了Python OpenCV 調(diào)用攝像頭并截圖保存功能,本文通過兩段實例代碼給大家介紹的非常詳細,具有一定的參考借鑒價值,需要的朋友可以參考下2019-07-07python調(diào)用動態(tài)鏈接庫的基本過程詳解
這篇文章主要介紹了python調(diào)用動態(tài)鏈接庫的基本過程詳解,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2019-06-06Python大數(shù)據(jù)之使用lxml庫解析html網(wǎng)頁文件示例
這篇文章主要介紹了Python大數(shù)據(jù)之使用lxml庫解析html網(wǎng)頁文件,結(jié)合實例形式分析了Python大數(shù)據(jù)操作中使用lxml庫解析html網(wǎng)頁具體步驟及相關注意事項,需要的朋友可以參考下2019-11-11Matlab中關于argmax、argmin函數(shù)的使用解讀
這篇文章主要介紹了Matlab中關于argmax、argmin函數(shù)的使用解讀,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-12-12Python中集合的創(chuàng)建及常用函數(shù)的使用詳解
這篇文章主要為大家詳細介紹了Python中集合的創(chuàng)建、使用和遍歷,集合常見的操作函數(shù),集合與列表,元組,字典的嵌套,感興趣的小伙伴可以了解一下2022-06-06