欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Python 基于線程的并行 threading模塊的用法

 更新時(shí)間:2025年06月12日 11:13:07   作者:V1ncent-CC  
threading模塊是Python的高級(jí)線程接口,提供線程對(duì)象和同步工具,本文主要介紹了Python 基于線程的并行 threading模塊的用法,感興趣的可以了解一下

threading模塊是基于_thread模塊的高級(jí)線程接口,相比于低層的_thread模塊,它提供了代表線程的對(duì)象和同步化工具,在threading模塊中,只要任何一個(gè)派生線程(守護(hù)線程除外)在運(yùn)行中,程序都不會(huì)退出,不再需要像_thread那樣控制主線程等待。

一、threading模塊基本用法

threading模塊基于_thread進(jìn)行了類封裝,其用于構(gòu)造線程的類為threading.Thread,通過(guò)創(chuàng)建類實(shí)例的方式來(lái)創(chuàng)建線程對(duì)象。

1.1 threading.Thread類

threading.Thread類的主要參數(shù)如下:

class threading.Thread(target=None, name=None, args=(), kwargs={}, *, daemon=None)

參數(shù)解釋:

  • target,用于定義子線程的活動(dòng),這應(yīng)該是個(gè)可調(diào)用的函數(shù)。
  • name,線程的名稱。
  • args,可調(diào)用函數(shù)的參數(shù)。
  • kwargs,可調(diào)用函數(shù)的關(guān)鍵字參數(shù)。
  • daemon,是否將線程設(shè)置為守護(hù)線程。

通過(guò)調(diào)用threading.Thread類創(chuàng)建出來(lái)的實(shí)例即是線程對(duì)象,線程對(duì)象創(chuàng)建后,需要調(diào)用.start方法啟動(dòng),這個(gè)方法會(huì)在獨(dú)立的線程中喚起run方法,因此有2種方法可以定義子線程的活動(dòng):

  • 向構(gòu)造類threading.Thread傳遞一個(gè)可調(diào)用對(duì)象(target參數(shù))。
  • 通過(guò)子類重載run方法。

下面通過(guò)案例演示2種用法。

1.2 用法1:通過(guò)threading.Thread定義子線程活動(dòng)

下面代碼先定義一個(gè)函數(shù)func,隨后調(diào)用threading.Thread創(chuàng)建2個(gè)線程對(duì)象,調(diào)用時(shí)通過(guò)target=func傳遞自定義函數(shù)(線程活動(dòng)),最后通過(guò)線程對(duì)象的.start方法啟動(dòng)線程:

import threading

def func(id):
    print('我是 {} 號(hào)子線程'.format(id))

t1 = threading.Thread(target=func, args=(1,))
t2 = threading.Thread(target=func, args=(2,))

t1.start()
t2.start()

在這里插入圖片描述

1.3 用法2:通過(guò)子類重載run方法定義子線程活動(dòng)

還是上面的例子,這次通過(guò)重載子類的run方法來(lái)定義子線程活動(dòng),當(dāng)調(diào)用線程對(duì)象的.start方法啟動(dòng)子線程時(shí),子線程會(huì)自動(dòng)調(diào)用.run方法。

import threading

def func(id):
    print('我是 {} 號(hào)子線程'.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('我是 {} 號(hào)子線程'.format(self.id))

t1 = MyThread(1)
t2 = MyThread(2)

# 啟動(dòng)子線程,會(huì)調(diào)用子類中的run方法
t1.start()
t2.start()

在這里插入圖片描述

二、threading模塊其他方法

threading模塊相對(duì)_thread模塊額外提供了一些線程狀態(tài)查詢和控制工具,下面介紹幾個(gè)主要方法。

2.1 共享訪問(wèn)控制 - threading.Lock

多線程必然會(huì)涉及到共享資源的訪問(wèn),threading模塊提供了一個(gè).Lock方法(和_thread.allocate_lock是同一個(gè)東西)用于創(chuàng)建鎖對(duì)象,通過(guò)鎖來(lái)控制共享資源的訪問(wèn),基于上面的類MyThread同時(shí)創(chuàng)建10個(gè)子線程:

for i in range(10):
    MyThread(i).start()

在這里插入圖片描述

可以看到上面的輸出出現(xiàn)了重疊,這是因?yàn)檫@10個(gè)子線程共享一個(gè)標(biāo)準(zhǔn)輸出流,可能出現(xiàn)同時(shí)打印的情況。下面把MyThread類改造一下,通過(guò).Lock對(duì)象來(lái)同步子線程的打印操作(每次打印前先獲取鎖,防止出現(xiàn)2個(gè)子線程同時(shí)打?。?/p>

class MyThread(threading.Thread):
    # 新增一個(gè)參數(shù)mutex,用于傳入鎖
    def __init__(self, id, mutex):
        self.id = id
        self.mutex = mutex
        threading.Thread.__init__(self)
    
    # 重載run方法
    def run(self):
        # 通過(guò)with語(yǔ)句管理鎖,打印前先獲取鎖,打印完成釋放
        with self.mutex:
            print('我是 {} 號(hào)子線程'.format(self.id))

# 創(chuàng)建一個(gè)鎖對(duì)象
mutex = threading.Lock()

for i in range(10):
    # 每個(gè)子線程啟動(dòng)時(shí)都傳入該鎖
    MyThread(i, mutex).start()

在這里插入圖片描述

  • mutex = threading.Lock() 創(chuàng)建了一個(gè)鎖對(duì)象,并在創(chuàng)建子線程時(shí)傳入(這10個(gè)子線程傳入的是同一把鎖)。
  • 子類的run方法,在執(zhí)行print語(yǔ)句前新增了with self.mutex,這會(huì)嘗試獲取鎖,如果當(dāng)前鎖被其他子線程占用(正在打?。?,那么它會(huì)等待。
  • 鎖對(duì)象也可以通過(guò).acuqure和.release方法手動(dòng)獲取和釋放,但建議還是使用with來(lái)管理(方便)。

2.2 阻塞方法 - threading.Thread.join

每個(gè)線程對(duì)象都有一個(gè)join方法,這個(gè)方法會(huì)阻塞調(diào)用者,直到線程終結(jié),這對(duì)于主線程來(lái)說(shuō)是一個(gè)信號(hào),通過(guò)join方法可以用來(lái)監(jiān)控子線程的完成情況,適合執(zhí)行在子線程完成后再執(zhí)行的動(dòng)作。

下面改造一下子類的run方法,讓每個(gè)線程打印前隨機(jī)等待1-5秒,然后調(diào)用Thread.join方法,這個(gè)方法會(huì)阻塞主線程(等待子線程完成),當(dāng)所有子線程執(zhí)行完畢時(shí)(.join方法返回),立刻打印"所有子線程執(zhí)行完畢"。

下面代碼在run方法的print之前加入了time.sleep(random.randint(1,5))讓子線程隨機(jī)睡眠1-5秒,因此子線程的結(jié)束時(shí)間是不確定的:

import time, random
class MyThread(threading.Thread):
    # 新增一個(gè)參數(shù)mutex,用于傳入鎖
    def __init__(self, id):
        self.id = id
        threading.Thread.__init__(self)
    
    # 重載run方法
    def run(self):
            # 打印之前隨機(jī)睡眠1-5秒
            time.sleep(random.randint(1,5))
            print('我是 {} 號(hào)子線程'.format(self.id))

threads = []

for i in range(10):
    # 每個(gè)子線程啟動(dòng)時(shí)都傳入該鎖
    ti = MyThread(i)
    threads.append(ti)
    ti.start()

print("開(kāi)始等待子線程執(zhí)行...")    
for thread in threads:
    # 針對(duì)每個(gè)子線程都會(huì)調(diào)用.join方法,所有子線程結(jié)束后,才會(huì)繼續(xù)向下執(zhí)行
    thread.join()
print("所有子線程執(zhí)行完畢...")    

在這里插入圖片描述

可以看到通過(guò)Thread.join方法阻塞主線程,可以保證在所有子線程都執(zhí)行完畢后,才打印"所有子線程執(zhí)行完畢…"。

以上即是threading模塊的基本用法,子線程還有.is_alive方法用來(lái)檢測(cè)是否存活,另外還有遞歸鎖可以用來(lái)嵌套獲取鎖,有興趣的同學(xué)可以深入研究一下。

最后:由于Cpython的中存在"全局解釋器鎖(GIL)",這個(gè)會(huì)限制利用多核CPU的計(jì)算資源(Python4.0可能會(huì)修復(fù)),因此多線程比較適合I/O密集型任務(wù),對(duì)于CPU密集型任務(wù),推薦還是使用多進(jìn)程并發(fā)(multiprocessing模塊)。

到此這篇關(guān)于Python 基于線程的并行 threading模塊的用法的文章就介紹到這了,更多相關(guān)Python 線程并行threading用法內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評(píng)論