最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Python多線程與同步機制淺析

 更新時間:2022年12月22日 16:38:42   作者:alwaysrun  
線程(Thread)是操作系統(tǒng)能夠進行運算調(diào)度的最小單位;線程自己不擁有系統(tǒng)資源,只擁有一點兒在運行中必不可少的資源,但它可與同屬一個進程的其它線程共享進程所擁有的全部資源

線程實現(xiàn)

Python中線程有兩種方式:函數(shù)或者用類來包裝線程對象。threading模塊中包含了豐富的多線程支持功能:

  • threading.currentThread(): 返回當(dāng)前線程;
  • threading.enumerate(): 返回包含正在運行的線程列表;
  • threading.activeCount(): 返回正在運行的線程數(shù)量,與len(threading.enumerate())等價。

Thread類

通過Thread類來處理線程,類中提供的一些方法:

  • run(): 用以表示線程執(zhí)行的方法(可重載實現(xiàn)實際功能);
  • start(): 啟動線程;
  • join([time]): 等待線程中止(或者超時);
  • isAlive(): 返回線程是否活動;
  • getName(): 返回線程名;
  • setName(): 設(shè)置線程名;
  • setDaemon(True):設(shè)置為后臺進程(必須在start調(diào)用前設(shè)定)。

函數(shù)方式

通過Thread直接構(gòu)造線程,然后通過start方法啟動線程:

threading.Thread(group=None, target=None, name=None, args=(), kwargs=None, *,daemon=None)

各參數(shù)說明:

  • group:指定線程隸屬的線程組(當(dāng)前忽略);
  • target:指定線程要調(diào)度的目標(biāo)方法(即實現(xiàn)功能的函數(shù));
  • args:傳遞給目標(biāo)方法的參數(shù)(以元組的方式);
  • kwargs:傳遞給目標(biāo)方法的參數(shù)(以字典的方式);
  • daemon:指定線程是否為后臺線程。
def simpleRoutine(name, delay):
    print(f"routine {name} starting...")
    time.sleep(delay)
    print(f"routine {name} finished")
if __name__ == '__main__':
    thrOne = threading.Thread(target=simpleRoutine, args=("First", 1))
    thrTwo = threading.Thread(target=simpleRoutine, args=("Two", 2))
    thrOne.start()
    thrTwo.start()
    thrOne.join()
    thrTwo.join()

繼承方式

直接繼承Thread,創(chuàng)建一個新的子類(主要實現(xiàn)run方法):

class SimpleThread (threading.Thread):
    def __init__(self, name, delay):
        # threading.Thread.__init__(self)
        super().__init__()
        self.name = name
        self.delay = delay
    def run(self):
        print(f"thread {self.name} starting...")
        time.sleep(self.delay)
        print(f"thread {self.name} finished")
if __name__ == '__main__':
    thrOne = SimpleThread("First", 2)
    thrTwo = SimpleThread("Second", 2)
    thrOne.start()
    thrTwo.start()
    thrOne.join()
    thrTwo.join()

同步機制

當(dāng)多個線程同時修改同一條數(shù)據(jù)時可能會出現(xiàn)臟數(shù)據(jù);所以,就需要線程鎖,即同一時刻只允許一個線程執(zhí)行操作。

同步鎖Lock

threading提供了Lock和RLock(可重入鎖)兩個類,它們都提供了如下兩個方法來加鎖和釋放鎖:

  • acquire(blocking=True, timeout=-1):加鎖,其中 timeout 參數(shù)指定加鎖多少秒。
  • release():釋放鎖。

兩種使用鎖的方式:

gCount = 0
def PlusOne(locker):
    global gCount
      with locker:
          gCount += 1、
def MinusOne(locker):
    global gCount
      if locker.acquire():
          gCount -= 1
          locker.release()

條件變量Condition

Condition對象內(nèi)部維護了一個鎖(構(gòu)造時可傳遞一個Lock/RLock對象,否則內(nèi)部會自行創(chuàng)建一個RLock)和一個waiting池:

  • 通過acquire獲得Condition對象;
  • 當(dāng)調(diào)用wait方法時,線程會釋放Condition內(nèi)部的鎖并進入blocked狀態(tài),同時在waiting池中記錄這個線程;
  • 當(dāng)調(diào)用notify方法時,Condition對象會從waiting池中挑選一個線程,通知其調(diào)用acquire方法嘗試取到鎖。

Condition對象:

__init__(self,lock=None):Condition類總是與一個鎖相關(guān)聯(lián)(若不指定lock參數(shù),會自動創(chuàng)建一個與之綁定的RLock對象);

acquire(timeout):調(diào)用關(guān)聯(lián)鎖的acquire()方法;

release():調(diào)用關(guān)聯(lián)鎖的release()方法

wait(timeout):線程掛起,直到收到一個notify通知或超時才會被喚醒;必須在已獲得鎖的前提下調(diào)用;

notify(n=1):喚醒waiting池中的n個正在等待的線程并通知它:

  • 收到通知的線程將自動調(diào)用acquire()方法嘗試加鎖;
  • 若waiting池中有多個線程,隨機選擇n個喚醒;
  • 必須在已獲得鎖的前提下調(diào)用,否則將引發(fā)錯誤。

notify_all():通知所有線程。

class Producer(threading.Thread):
    def __init__(self, cond, storage):
        threading.Thread.__init__(self)
        self.cond = cond
        self.storage = storage
    def run(self):
        label = 1
        while True:
            with self.cond:
                if len(self.storage) < 10:
                    self.storage.append(label)
                    print(f"<- Produce {label} product")
                    label += 1
                    self.cond.notify(2)
                else:
                    print(f"<- storage full: Has Produced {label - 1} product")
                    self.cond.notify_all()
                    self.cond.wait()
                time.sleep(0.4)
class Consumer(threading.Thread):
    def __init__(self, name, cond, storage):
        threading.Thread.__init__(self)
        self.name = name
        self.cond = cond
        self.storage = storage
    def run(self):
        while True:
            if self.cond.acquire():
                if len(self.storage) > 1:
                    pro = self.storage.pop(0)
                    print(f"-> {self.name} consumed {pro}")
                    self.cond.notify()
                else:
                    print(f"-> {self.name} storage empty: no product to consume")
                    self.cond.wait()
                self.cond.release()
                time.sleep(1)

信號量Semaphore

信號量對象內(nèi)部維護一個計數(shù)器:

  • acquire(blocking=True,timeout=None)時減1,當(dāng)計數(shù)為0就阻塞請求的線程;
  • release()時加1,當(dāng)計數(shù)大于0恢復(fù)被阻塞的線程;

threading中有Semaphore和BoundedSemaphore兩個信號量;BoundedSemaphore限制了release的次數(shù),任何時候計數(shù)器的值,都不不能大于初始值(release時會檢測計數(shù)器的值,若大于等于初始值,則拋出ValueError異常)。

通過Semaphore維護生產(chǎn)(release一個)、消費(acquire一個)量:

# products = threading.Semaphore(0)
def produceOne(label, sem: threading.Semaphore):
    sem.release()
    print(f"{label} produce one")
def consumeOne(label, sem: threading.Semaphore):
    sem.acquire()
    print(f"{label} consume one")

通過BoundedSemaphore來控制并發(fā)數(shù)量(最多有Semaphore初始值數(shù)量的線程并發(fā)):

# runner = threading.BoundedSemaphore(3)
def runBound(name, sem: threading.BoundedSemaphore):
    with sem:
        print(f"{name} is running")
        time.sleep(1)
        print(f"{name} finished")

事件Event

事件對象內(nèi)部有個標(biāo)志字段,用于線程等待事件的發(fā)生:

  • isSet():返回event的狀態(tài)值;
  • wait():狀態(tài)為False時,一直阻塞;否則立即返回;
  • set(): 設(shè)置狀態(tài)值為True,激活所有被阻塞的線程;
  • clear():恢復(fù)狀態(tài)值為False。

多線程等待事件發(fā)生,然后開始執(zhí)行:

def waiters(name, evt: threading.Event):
    evt.wait()
    print(f"{name} is running")
    time.sleep(1)
    print(f"{name} finished")
def starting(evt: threading.Event):
    evt.set()
    print("event is set")

屏障Barrier

屏障用于設(shè)定等待線程數(shù)量,當(dāng)數(shù)量達到指定值時,開始執(zhí)行:

threading.Barrier(parties, action=None, timeout=None)

屏障屬性與方法:

  • wait(timeout=None):等待通過屏障;線程被阻塞,直到阻塞的數(shù)量達到parties時,被阻塞的線程被同時全部釋放;
  • reset():重置屏障到默認(rèn)的空狀態(tài);
  • abort():將障礙置為斷開狀態(tài);導(dǎo)致等待的線程引發(fā)BrokenBarrierError異常;
  • partier():通過障礙所需的線程數(shù);
  • n_waiting():當(dāng)前在屏障中等待的線程數(shù);
  • broken():如果屏障處于斷開狀態(tài),則返回True。
def waitBarrier(name, barr: threading.Barrier):
    print(f"{name} waiting for open")
    try:
        barr.wait()
        print(f"{name} running")
        time.sleep(5)
    except threading.BrokenBarrierError:
        print(f"{name} exception")
    print(f"{name} finished")

GIL全局解釋器鎖

GIL(Global Interpreter Lock,全局解釋器鎖);cpython中,某個線程想要執(zhí)行,必須先拿到GIL(可以把GIL看作是“通行證”)。每次釋放GIL鎖,線程都要進行鎖競爭,切換線程,會消耗資源。

由于GIL鎖的存在,python里一個進程永遠(yuǎn)只能同時執(zhí)行一個線程(拿到GIL的線程),這就是為什么在多核CPU上,python的多線程效率并不高:

  • CPU密集型代碼:由于計算工作多,會很快用完時間片,然后觸發(fā)GIL的釋放與再競爭;
  • IO密集型代碼(文件處理、網(wǎng)絡(luò)爬蟲等):多線程能夠有效提升效率(單線程下有IO操作會進行IO等待,造成不必要的時間浪費,而開啟多線程能在線程A等待時,自動切換到線程B,可以不浪費CPU的資源,從而能提升程序執(zhí)行效率)。

python在使用多線程的時候,調(diào)用的是c語言的原生線程:

  • 拿到公共數(shù)據(jù)
  • 申請GIL
  • python解釋器調(diào)用os原生線程
  • os操作cpu執(zhí)行運算
  • 當(dāng)線程執(zhí)行時間到后,就進行切換(context switch)

到此這篇關(guān)于Python多線程與同步機制淺析的文章就介紹到這了,更多相關(guān)Python多線程內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 如何使用OpenCV實現(xiàn)手勢音量控制

    如何使用OpenCV實現(xiàn)手勢音量控制

    今天來學(xué)習(xí)一下如何使用OpenCV實現(xiàn)手勢音量控制,本次實驗需要使用OpenCV和mediapipe庫進行手勢識別,并利用手勢距離控制電腦音量,感興趣的朋友跟隨小編一起看看吧
    2023-11-11
  • Python調(diào)用C++,通過Pybind11制作Python接口

    Python調(diào)用C++,通過Pybind11制作Python接口

    今天小編就為大家分享一篇關(guān)于Python調(diào)用C++,通過Pybind11制作Python接口,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧
    2018-10-10
  • pytorch 更改預(yù)訓(xùn)練模型網(wǎng)絡(luò)結(jié)構(gòu)的方法

    pytorch 更改預(yù)訓(xùn)練模型網(wǎng)絡(luò)結(jié)構(gòu)的方法

    今天小編就為大家分享一篇pytorch 更改預(yù)訓(xùn)練模型網(wǎng)絡(luò)結(jié)構(gòu)的方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2019-08-08
  • python中的循環(huán)結(jié)構(gòu)問題

    python中的循環(huán)結(jié)構(gòu)問題

    這篇文章主要介紹了python中的循環(huán)結(jié)構(gòu)問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-03-03
  • Python struct模塊解析

    Python struct模塊解析

    我們知道python只定義了6種數(shù)據(jù)類型,字符串,整數(shù),浮點數(shù),列表,元組,字典。但是C語言中有些字節(jié)型的變量,在python中該如何實現(xiàn)呢?這點頗為重要,特別是要在網(wǎng)絡(luò)上進行數(shù)據(jù)傳輸?shù)脑挕?/div> 2014-06-06
  • python 裝飾器功能以及函數(shù)參數(shù)使用介紹

    python 裝飾器功能以及函數(shù)參數(shù)使用介紹

    之前學(xué)習(xí)編程語言大多也就是學(xué)的很淺很淺,基本上也是很少涉及到裝飾器這些的類似的內(nèi)容??偸怯X得是一樣很神奇的東西,舍不得學(xué)(嘿嘿)。今天看了一下書籍。發(fā)現(xiàn)道理還是很簡單的
    2012-01-01
  • python 爬蟲網(wǎng)頁登陸的簡單實現(xiàn)

    python 爬蟲網(wǎng)頁登陸的簡單實現(xiàn)

    這篇文章主要介紹了python 爬蟲網(wǎng)頁登陸的簡單實現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-11-11
  • 進一步探究Python的裝飾器的運用

    進一步探究Python的裝飾器的運用

    這篇文章主要介紹了更為深入的Python的裝飾器的運用,Python的裝飾器是Python學(xué)習(xí)進階當(dāng)中的重要知識點,需要的朋友可以參考下
    2015-05-05
  • python 如何對Series中的每一個數(shù)據(jù)做運算

    python 如何對Series中的每一個數(shù)據(jù)做運算

    這篇文章主要介紹了python 實現(xiàn)對Series中的每一個數(shù)據(jù)做運算操作,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-05-05
  • django 多數(shù)據(jù)庫配置教程

    django 多數(shù)據(jù)庫配置教程

    今天小編就為大家分享一篇django 多數(shù)據(jù)庫配置教程,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2018-05-05

最新評論

黄梅县| 崇礼县| 蓬莱市| 南昌市| 乐至县| 西城区| 花莲市| 郎溪县| 罗田县| 承德市| 县级市| 疏勒县| 堆龙德庆县| 马边| 文安县| 太康县| 甘孜| 龙江县| 桐梓县| 汶上县| 新昌县| 泰兴市| 新平| 凤阳县| 柞水县| 柘城县| 太仓市| 鸡西市| 大姚县| 浙江省| 收藏| 沙洋县| 七台河市| 运城市| 阿坝县| 瑞丽市| 新宁县| 海伦市| 松桃| 长宁县| 肇州县|