色哟哟视频在线观看-色哟哟视频在线-色哟哟欧美15最新在线-色哟哟免费在线观看-国产l精品国产亚洲区在线观看-国产l精品国产亚洲区久久

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線(xiàn)課程
  • 觀看技術(shù)視頻
  • 寫(xiě)文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

Python、線(xiàn)程和全局解釋器鎖

馬哥Linux運(yùn)維 ? 來(lái)源:未知 ? 作者:李倩 ? 2018-11-19 18:02 ? 次閱讀

引言&動(dòng)機(jī)

考慮一下這個(gè)場(chǎng)景,我們有10000條數(shù)據(jù)需要處理,處理每條數(shù)據(jù)需要花費(fèi)1秒,但讀取數(shù)據(jù)只需要0.1秒,每條數(shù)據(jù)互不干擾。該如何執(zhí)行才能花費(fèi)時(shí)間最短呢?

在多線(xiàn)程(MT)編程出現(xiàn)之前,電腦程序的運(yùn)行由一個(gè)執(zhí)行序列組成,執(zhí)行序列按順序在主機(jī)的中央處理器(CPU)中運(yùn)行。無(wú)論是任務(wù)本身要求順序執(zhí)行還是整個(gè)程序是由多個(gè)子任務(wù)組成,程序都是按這種方式執(zhí)行的。即使子任務(wù)相互獨(dú)立,互相無(wú)關(guān)(即,一個(gè)子任務(wù)的結(jié)果不影響其它子 任務(wù)的結(jié)果)時(shí)也是這樣。

對(duì)于上邊的問(wèn)題,如果使用一個(gè)執(zhí)行序列來(lái)完成,我們大約需要花費(fèi) 10000*0.1 + 10000 = 11000 秒。這個(gè)時(shí)間顯然是太長(zhǎng)了。

那我們有沒(méi)有可能在執(zhí)行計(jì)算的同時(shí)取數(shù)據(jù)呢?或者是同時(shí)處理幾條數(shù)據(jù)呢?如果可以,這樣就能大幅提高任務(wù)的效率。這就是多線(xiàn)程編程的目的。

對(duì)于本質(zhì)上就是異步的, 需要有多個(gè)并發(fā)事務(wù),各個(gè)事務(wù)的運(yùn)行順序可以是不確定的,隨機(jī)的,不可預(yù)測(cè)的問(wèn)題,多線(xiàn)程是最理想的解決方案。這樣的任務(wù)可以被分成多個(gè)執(zhí)行流,每個(gè)流都有一個(gè)要完成的目標(biāo),然后將得到的結(jié)果合并,得到最終的結(jié)果。

線(xiàn)程和進(jìn)程

什么是進(jìn)程

進(jìn)程(有時(shí)被稱(chēng)為重量級(jí)進(jìn)程)是程序的一次 執(zhí)行。每個(gè)進(jìn)程都有自己的地址空間,內(nèi)存,數(shù)據(jù)棧以及其它記錄其運(yùn)行軌跡的輔助數(shù)據(jù)。操作系 統(tǒng)管理在其上運(yùn)行的所有進(jìn)程,并為這些進(jìn)程公平地分配時(shí)間。進(jìn)程也可以通過(guò) fork 和 spawn 操作 來(lái)完成其它的任務(wù)。不過(guò)各個(gè)進(jìn)程有自己的內(nèi)存空間,數(shù)據(jù)棧等,所以只能使用進(jìn)程間通訊(IPC), 而不能直接共享信息

什么是線(xiàn)程

線(xiàn)程(有時(shí)被稱(chēng)為輕量級(jí)進(jìn)程)跟進(jìn)程有些相似,不同的是,所有的線(xiàn)程運(yùn)行在同一個(gè)進(jìn)程中, 共享相同的運(yùn)行環(huán)境。它們可以想像成是在主進(jìn)程或“主線(xiàn)程”中并行運(yùn)行的“迷你進(jìn)程”。

線(xiàn)程狀態(tài)如圖

線(xiàn)程有開(kāi)始,順序執(zhí)行和結(jié)束三部分。它有一個(gè)自己的指令指針,記錄自己運(yùn)行到什么地方。 線(xiàn)程的運(yùn)行可能被搶占(中斷),或暫時(shí)的被掛起(也叫睡眠),讓其它的線(xiàn)程運(yùn)行,這叫做讓步。 一個(gè)進(jìn)程中的各個(gè)線(xiàn)程之間共享同一片數(shù)據(jù)空間,所以線(xiàn)程之間可以比進(jìn)程之間更方便地共享數(shù)據(jù)以及相互通訊。

當(dāng)然,這樣的共享并不是完全沒(méi)有危險(xiǎn)的。如果多個(gè)線(xiàn)程共同訪(fǎng)問(wèn)同一片數(shù)據(jù),則由于數(shù)據(jù)訪(fǎng) 問(wèn)的順序不一樣,有可能導(dǎo)致數(shù)據(jù)結(jié)果的不一致的問(wèn)題。這叫做競(jìng)態(tài)條件(race condition)。

線(xiàn)程一般都是并發(fā)執(zhí)行的,不過(guò)在單 CPU 的系統(tǒng)中,真正的并發(fā)是不可能的,每個(gè)線(xiàn)程會(huì)被安排成每次只運(yùn)行一小會(huì),然后就把 CPU 讓出來(lái),讓其它的線(xiàn)程去運(yùn)行。由于有的函數(shù)會(huì)在完成之前阻塞住,在沒(méi)有特別為多線(xiàn)程做修改的情 況下,這種“貪婪”的函數(shù)會(huì)讓 CPU 的時(shí)間分配有所傾斜。導(dǎo)致各個(gè)線(xiàn)程分配到的運(yùn)行時(shí)間可能不 盡相同,不盡公平。

Python、線(xiàn)程和全局解釋器鎖

全局解釋器鎖(GIL)

首先需要明確的一點(diǎn)是GIL并不是Python的特性,它是在實(shí)現(xiàn)Python解析器(CPython)時(shí)所引入的一個(gè)概念。就好比C++是一套語(yǔ)言(語(yǔ)法)標(biāo)準(zhǔn),但是可以用不同的編譯器來(lái)編譯成可執(zhí)行代碼。同樣一段代碼可以通過(guò)CPython,PyPy,Psyco等不同的Python執(zhí)行環(huán)境來(lái)執(zhí)行(其中的JPython就沒(méi)有GIL)。

那么CPython實(shí)現(xiàn)中的GIL又是什么呢?GIL全稱(chēng)Global Interpreter Lock為了避免誤導(dǎo),我們還是來(lái)看一下官方給出的解釋?zhuān)?/p>

In CPython, the global interpreter lock, or GIL, is a mutex that prevents multiple native threads from executing Python bytecodes at once. This lock is necessary mainly because CPython’s memory management is not thread-safe. (However, since the GIL exists, other features have grown to depend on the guarantees that it enforces.)

盡管Python完全支持多線(xiàn)程編程, 但是解釋器的C語(yǔ)言實(shí)現(xiàn)部分在完全并行執(zhí)行時(shí)并不是線(xiàn)程安全的。 實(shí)際上,解釋器被一個(gè)全局解釋器鎖保護(hù)著,它確保任何時(shí)候都只有一個(gè)Python線(xiàn)程執(zhí)行。

在多線(xiàn)程環(huán)境中,Python 虛擬機(jī)按以下方式執(zhí)行:

1.設(shè)置GIL

2.切換到一個(gè)線(xiàn)程去執(zhí)行

3.運(yùn)行

指定數(shù)量的字節(jié)碼指令

線(xiàn)程主動(dòng)讓出控制(可以調(diào)用time.sleep(0))

4.把線(xiàn)程設(shè)置完睡眠狀態(tài)

5.解鎖GIL

6.再次重復(fù)以上步驟

對(duì)所有面向 I/O 的(會(huì)調(diào)用內(nèi)建的操作系統(tǒng) C 代碼的)程序來(lái)說(shuō),GIL 會(huì)在這個(gè) I/O 調(diào)用之 前被釋放,以允許其它的線(xiàn)程在這個(gè)線(xiàn)程等待 I/O 的時(shí)候運(yùn)行。如果某線(xiàn)程并未使用很多 I/O 操作, 它會(huì)在自己的時(shí)間片內(nèi)一直占用處理器(和 GIL)。也就是說(shuō),I/O 密集型的 Python 程序比計(jì)算密集 型的程序更能充分利用多線(xiàn)程環(huán)境的好處。

退出線(xiàn)程

當(dāng)一個(gè)線(xiàn)程結(jié)束計(jì)算,它就退出了。線(xiàn)程可以調(diào)用 thread.exit()之類(lèi)的退出函數(shù),也可以使用 Python 退出進(jìn)程的標(biāo)準(zhǔn)方法,如 sys.exit()或拋出一個(gè) SystemExit 異常等。不過(guò),你不可以直接 “殺掉”(“kill”)一個(gè)線(xiàn)程。

在 Python 中使用線(xiàn)程

在 Win32 和 Linux, Solaris, MacOS, *BSD 等大多數(shù)類(lèi) Unix 系統(tǒng)上運(yùn)行時(shí),Python 支持多線(xiàn)程 編程。Python 使用 POSIX 兼容的線(xiàn)程,即 pthreads。

默認(rèn)情況下,只要在解釋器中

如果沒(méi)有報(bào)錯(cuò),則說(shuō)明線(xiàn)程可用。

Python 的 threading 模塊

Python 供了幾個(gè)用于多線(xiàn)程編程的模塊,包括 thread, threading 和 Queue 等。thread 和 threading 模塊允許程序員創(chuàng)建和管理線(xiàn)程。thread 模塊 供了基本的線(xiàn)程和鎖的支持,而 threading 供了更高級(jí)別,功能更強(qiáng)的線(xiàn)程管理的功能。Queue 模塊允許用戶(hù)創(chuàng)建一個(gè)可以用于多個(gè)線(xiàn)程之間 共享數(shù)據(jù)的隊(duì)列數(shù)據(jù)結(jié)構(gòu)。

核心 示:避免使用 thread 模塊

出于以下幾點(diǎn)考慮,我們不建議您使用 thread 模塊。

1.更高級(jí)別的 threading 模塊更為先 進(jìn),對(duì)線(xiàn)程的支持更為完善,而且使用 thread 模塊里的屬性有可能會(huì)與 threading 出現(xiàn)沖突。其次, 低級(jí)別的 thread 模塊的同步原語(yǔ)很少(實(shí)際上只有一個(gè)),而 threading 模塊則有很多。

2.對(duì)于你的進(jìn)程什么時(shí)候應(yīng)該結(jié)束完全沒(méi)有控制,當(dāng)主線(xiàn)程結(jié)束 時(shí),所有的線(xiàn)程都會(huì)被強(qiáng)制結(jié)束掉,沒(méi)有警告也不會(huì)有正常的清除工作。我們之前說(shuō)過(guò),至少 threading 模塊能確保重要的子線(xiàn)程退出后進(jìn)程才退出。

thread 模塊

除了產(chǎn)生線(xiàn)程外,thread 模塊也提供了基本的同步數(shù) 據(jù)結(jié)構(gòu)鎖對(duì)象(lock object,也叫原語(yǔ)鎖,簡(jiǎn)單鎖,互斥鎖,互斥量,二值信號(hào)量)。

thread 模塊函數(shù)

start_new_thread(function, args, kwargs=None):產(chǎn)生一個(gè)新的線(xiàn)程,在新線(xiàn)程中用指定的參數(shù)和可選的 kwargs 來(lái)調(diào)用這個(gè)函數(shù)。

allocate_lock():分配一個(gè) LockType 類(lèi)型的鎖對(duì)象

exit():讓線(xiàn)程退出

acquire(wait=None):嘗試獲取鎖對(duì)象

locked():如果獲取了鎖對(duì)象返回 True,否則返回 False

release():釋放鎖

下面是一個(gè)使用 thread 的例子:

start_new_thread()要求一定要有前兩個(gè)參數(shù)。所以,就算我們想要運(yùn)行的函數(shù)不要參數(shù),也要傳一個(gè)空的元組。為什么要加上sleep(6)這一句呢? 因?yàn)椋绻覀儧](méi)有讓主線(xiàn)程停下來(lái),那主線(xiàn)程就會(huì)運(yùn)行下一條語(yǔ)句,顯示 “all done”,然后就關(guān)閉運(yùn)行著 loop()和 loop1()的兩個(gè)線(xiàn)程,退出了。

我們有沒(méi)有更好的辦法替換使用sleep() 這種不靠譜的同步方式呢?答案是使用鎖,使用了鎖,我們就可以在兩個(gè)線(xiàn)程都退出之后馬上退出。

為什么我們不在創(chuàng)建鎖的循環(huán)里創(chuàng)建線(xiàn)程呢?有以下幾個(gè)原因:

1.我們想到實(shí)現(xiàn)線(xiàn)程的同步,所以要讓“所有的馬同時(shí)沖出柵欄”。

2.獲取鎖要花一些時(shí)間,如果你的 線(xiàn)程退出得“太快”,可能會(huì)導(dǎo)致還沒(méi)有獲得鎖,線(xiàn)程就已經(jīng)結(jié)束了的情況。

threading 模塊

threading 模塊不僅提供了 Thread 類(lèi),還 供了各 種非常好用的同步機(jī)制。

下面是threading 模塊里所有的對(duì)象:

Thread: 表示一個(gè)線(xiàn)程的執(zhí)行的對(duì)象

Lock: 鎖原語(yǔ)對(duì)象(跟 thread 模塊里的鎖對(duì)象相同)

RLock: 可重入鎖對(duì)象。使單線(xiàn)程可以再次獲得已經(jīng)獲得了的鎖(遞歸鎖定)。

Condition: 條件變量對(duì)象能讓一個(gè)線(xiàn)程停下來(lái),等待其它線(xiàn)程滿(mǎn)足了某個(gè)“條件”。 如,狀態(tài)的改變或值的改變。

Event: 通用的條件變量。多個(gè)線(xiàn)程可以等待某個(gè)事件的發(fā)生,在事件發(fā)生后, 所有的線(xiàn)程都會(huì)被激活。

Semaphore: 為等待鎖的線(xiàn)程 供一個(gè)類(lèi)似“等候室”的結(jié)構(gòu)

BoundedSemaphore: 與 Semaphore 類(lèi)似,只是它不允許超過(guò)初始值

Timer: 與 Thread 相似,只是,它要等待一段時(shí)間后才開(kāi)始運(yùn)行。

守護(hù)線(xiàn)程

另一個(gè)避免使用 thread 模塊的原因是,它不支持守護(hù)線(xiàn)程。當(dāng)主線(xiàn)程退出時(shí),所有的子線(xiàn)程不 論它們是否還在工作,都會(huì)被強(qiáng)行退出。有時(shí),我們并不期望這種行為,這時(shí),就引入了守護(hù)線(xiàn)程 的概念threading 模塊支持守護(hù)線(xiàn)程,它們是這樣工作的:守護(hù)線(xiàn)程一般是一個(gè)等待客戶(hù)請(qǐng)求的服務(wù)器, 如果沒(méi)有客戶(hù) 出請(qǐng)求,它就在那等著。如果你設(shè)定一個(gè)線(xiàn)程為守護(hù)線(xiàn)程,就表示你在說(shuō)這個(gè)線(xiàn)程 是不重要的,在進(jìn)程退出的時(shí)候,不用等待這個(gè)線(xiàn)程退出。如果你的主線(xiàn)程要退出的時(shí)候,不用等待那些子線(xiàn)程完成,那就設(shè)定這些線(xiàn)程的 daemon 屬性。 即,在線(xiàn)程開(kāi)始(調(diào)用 thread.start())之前,調(diào)用 setDaemon()函數(shù)設(shè)定線(xiàn)程的 daemon 標(biāo)志 (thread.setDaemon(True))就表示這個(gè)線(xiàn)程“不重要”如果你想要等待子線(xiàn)程完成再退出,那就什么都不用做,或者顯式地調(diào)用 thread.setDaemon(False)以保證其 daemon 標(biāo)志為 False。你可以調(diào)用 thread.isDaemon()函數(shù)來(lái)判 斷其 daemon 標(biāo)志的值。新的子線(xiàn)程會(huì)繼承其父線(xiàn)程的 daemon 標(biāo)志。整個(gè) Python 會(huì)在所有的非守護(hù) 線(xiàn)程退出后才會(huì)結(jié)束,即進(jìn)程中沒(méi)有非守護(hù)線(xiàn)程存在的時(shí)候才結(jié)束。

Thread 類(lèi)

Thread類(lèi)提供了以下方法:

run(): 用以表示線(xiàn)程活動(dòng)的方法。

start():啟動(dòng)線(xiàn)程活動(dòng)。

join([time]): 等待至線(xiàn)程中止。這阻塞調(diào)用線(xiàn)程直至線(xiàn)程的join() 方法被調(diào)用中止-正常退出或者拋出未處理的異常-或者是可選的超時(shí)發(fā)生。

is_alive(): 返回線(xiàn)程是否活動(dòng)的。

name(): 設(shè)置/返回線(xiàn)程名。

daemon(): 返回/設(shè)置線(xiàn)程的 daemon 標(biāo)志,一定要在調(diào)用 start()函數(shù)前設(shè)置

用 Thread 類(lèi),你可以用多種方法來(lái)創(chuàng)建線(xiàn)程。我們?cè)谶@里介紹三種比較相像的方法。

創(chuàng)建一個(gè)Thread的實(shí)例,傳給它一個(gè)函數(shù)

創(chuàng)建一個(gè)Thread的實(shí)例,傳給它一個(gè)可調(diào)用的類(lèi)對(duì)象

從Thread派生出一個(gè)子類(lèi),創(chuàng)建一個(gè)這個(gè)子類(lèi)的實(shí)例

下邊是三種不同方式的創(chuàng)建線(xiàn)程的示例:

與傳一個(gè)函數(shù)很相似的另一個(gè)方法是在創(chuàng)建線(xiàn)程的時(shí)候,傳一個(gè)可調(diào)用的類(lèi)的實(shí)例供線(xiàn)程啟動(dòng) 的時(shí)候執(zhí)行——這是多線(xiàn)程編程的一個(gè)更為面向?qū)ο蟮姆椒āO鄬?duì)于一個(gè)或幾個(gè)函數(shù)來(lái)說(shuō),由于類(lèi) 對(duì)象里可以使用類(lèi)的強(qiáng)大的功能,可以保存更多的信息,這種方法更為靈活

最后一個(gè)例子介紹如何子類(lèi)化 Thread 類(lèi),這與上一個(gè)例子中的創(chuàng)建一個(gè)可調(diào)用的類(lèi)非常像。使 用子類(lèi)化創(chuàng)建線(xiàn)程(第 29-30 行)使代碼看上去更清晰明了。

active_count(): 當(dāng)前活動(dòng)的線(xiàn)程對(duì)象的數(shù)量

current_thread(): 返回當(dāng)前線(xiàn)程對(duì)象

enumerate(): 返回當(dāng)前活動(dòng)線(xiàn)程的列表

settrace(func): 為所有線(xiàn)程設(shè)置一個(gè)跟蹤函數(shù)

setprofile(func): 為所有線(xiàn)程設(shè)置一個(gè) profile 函數(shù)

Lock & RLock

原語(yǔ)鎖定是一個(gè)同步原語(yǔ),狀態(tài)是鎖定或未鎖定。兩個(gè)方法acquire()和release() 用于加鎖和釋放鎖。RLock 可重入鎖是一個(gè)類(lèi)似于Lock對(duì)象的同步原語(yǔ),但同一個(gè)線(xiàn)程可以多次調(diào)用。

Lock 不支持遞歸加鎖,也就是說(shuō)即便在同 線(xiàn)程中,也必須等待鎖釋放。通常建議改 RLock, 它會(huì)處理 “owning thread” 和 “recursion level” 狀態(tài),對(duì)于同 線(xiàn)程的多次請(qǐng)求鎖 為,只累加計(jì)數(shù)器。每次調(diào) release() 將遞減該計(jì)數(shù)器,直到 0 時(shí)釋放鎖,因此 acquire() 和 release() 必須 要成對(duì)出現(xiàn)。

Event

事件用于在線(xiàn)程間通信。一個(gè)線(xiàn)程發(fā)出一個(gè)信號(hào),其他一個(gè)或多個(gè)線(xiàn)程等待。Event 通過(guò)通過(guò) 個(gè)內(nèi)部標(biāo)記來(lái)協(xié)調(diào)多線(xiàn)程運(yùn) 。 法 wait() 阻塞線(xiàn)程執(zhí) ,直到標(biāo)記為 True。 set() 將標(biāo)記設(shè)為 True,clear() 更改標(biāo)記為 False。isSet() 用于判斷標(biāo)記狀態(tài)。

Condition

條件變量和 Lock 參數(shù)一樣,也是一個(gè),也是一個(gè)同步原語(yǔ),當(dāng)需要線(xiàn)程關(guān)注特定的狀態(tài)變化或事件的發(fā)生時(shí)使用這個(gè)鎖定。

可以認(rèn)為,除了Lock帶有的鎖定池外,Condition還包含一個(gè)等待池,池中的線(xiàn)程處于狀態(tài)圖中的等待阻塞狀態(tài),直到另一個(gè)線(xiàn)程調(diào)用notify()/notifyAll()通知;得到通知后線(xiàn)程進(jìn)入鎖定池等待鎖定。

構(gòu)造方法:Condition([lock/rlock])

Condition 有以下這些方法:

acquire([timeout])/release(): 調(diào)用關(guān)聯(lián)的鎖的相應(yīng)方法。

wait([timeout]): 調(diào)用這個(gè)方法將使線(xiàn)程進(jìn)入Condition的等待池等待通知,并釋放鎖。使用前線(xiàn)程必須已獲得鎖定,否則將拋出異常。

notify(): 調(diào)用這個(gè)方法將從等待池挑選一個(gè)線(xiàn)程并通知,收到通知的線(xiàn)程將自動(dòng)調(diào)用acquire()嘗試獲得鎖定(進(jìn)入鎖定池);其他線(xiàn)程仍然在等待池中。調(diào)用這個(gè)方法不會(huì)釋放鎖定。使用前線(xiàn)程必須已獲得鎖定,否則將拋出異常。

notifyAll(): 調(diào)用這個(gè)方法將通知等待池中所有的線(xiàn)程,這些線(xiàn)程都將進(jìn)入鎖定池嘗試獲得鎖定。調(diào)用這個(gè)方法不會(huì)釋放鎖定。使用前線(xiàn)程必須已獲得鎖定,否則將拋出異常。

只有獲取鎖的線(xiàn)程才能調(diào)用 wait() 和 notify(),因此必須在鎖釋放前調(diào)用。當(dāng) wait() 釋放鎖后,其他線(xiàn)程也可進(jìn)入 wait 狀態(tài)。notifyAll() 激活所有等待線(xiàn)程,讓它們?nèi)屾i然后完成后續(xù)執(zhí)行。

生產(chǎn)者-消費(fèi)者問(wèn)題和 Queue 模塊

現(xiàn)在我們用一個(gè)經(jīng)典的(生產(chǎn)者消費(fèi)者)例子來(lái)介紹一下 Queue模塊。

生產(chǎn)者消費(fèi)者的場(chǎng)景是: 生產(chǎn)者生產(chǎn)貨物,然后把貨物放到一個(gè)隊(duì)列之類(lèi)的數(shù)據(jù)結(jié)構(gòu)中,生產(chǎn)貨物所要花費(fèi)的時(shí)間無(wú)法預(yù)先確定。消費(fèi)者消耗生產(chǎn)者生產(chǎn)的貨物的時(shí)間也是不確定的。

常用的 Queue 模塊的屬性:

queue(size): 創(chuàng)建一個(gè)大小為size的Queue對(duì)象。

qsize(): 返回隊(duì)列的大小(由于在返回的時(shí)候,隊(duì)列可能會(huì)被其它線(xiàn)程修改,所以這個(gè)值是近似值)

empty(): 如果隊(duì)列為空返回 True,否則返回 False

full(): 如果隊(duì)列已滿(mǎn)返回 True,否則返回 False

put(item,block=0): 把item放到隊(duì)列中,如果給了block(不為0),函數(shù)會(huì)一直阻塞到隊(duì)列中有空間為止

get(block=0): 從隊(duì)列中取一個(gè)對(duì)象,如果給了 block(不為 0),函數(shù)會(huì)一直阻塞到隊(duì)列中有對(duì)象為止

Queue 模塊可以用來(lái)進(jìn)行線(xiàn)程間通訊,讓各個(gè)線(xiàn)程之間共享數(shù)據(jù)。

現(xiàn)在,我們創(chuàng)建一個(gè)隊(duì)列,讓 生產(chǎn)者(線(xiàn)程)把新生產(chǎn)的貨物放進(jìn)去供消費(fèi)者(線(xiàn)程)使用。

FAQ

1.進(jìn)程與線(xiàn)程。線(xiàn)程與進(jìn)程的區(qū)別是什么?

進(jìn)程(有時(shí)被稱(chēng)為重量級(jí)進(jìn)程)是程序的一次 執(zhí)行。每個(gè)進(jìn)程都有自己的地址空間,內(nèi)存,數(shù)據(jù)棧以及其它記錄其運(yùn)行軌跡的輔助數(shù)據(jù)。線(xiàn)程(有時(shí)被稱(chēng)為輕量級(jí)進(jìn)程)跟進(jìn)程有些相似,不同的是,所有的線(xiàn)程運(yùn)行在同一個(gè)進(jìn)程中, 共享相同的運(yùn)行環(huán)境。它們可以想像成是在主進(jìn)程或“主線(xiàn)程”中并行運(yùn)行的“迷你進(jìn)程”。

2.Python 的線(xiàn)程。在 Python 中,哪一種多線(xiàn)程的程序表現(xiàn)得更好,I/O 密集型的還是計(jì)算 密集型的?

由于GIL的緣故,對(duì)所有面向 I/O 的(會(huì)調(diào)用內(nèi)建的操作系統(tǒng) C 代碼的)程序來(lái)說(shuō),GIL 會(huì)在這個(gè) I/O 調(diào)用之 前被釋放,以允許其它的線(xiàn)程在這個(gè)線(xiàn)程等待 I/O 的時(shí)候運(yùn)行。如果某線(xiàn)程并未使用很多 I/O 操作, 它會(huì)在自己的時(shí)間片內(nèi)一直占用處理器(和 GIL)。也就是說(shuō),I/O 密集型的 Python 程序比計(jì)算密集 型的程序更能充分利用多線(xiàn)程環(huán)境的好處。

3.線(xiàn)程。你認(rèn)為,多 CPU 的系統(tǒng)與一般的系統(tǒng)有什么大的不同?多線(xiàn)程的程序在這種系統(tǒng)上的表現(xiàn)會(huì)怎么樣?

Python的線(xiàn)程就是C語(yǔ)言的一個(gè)pthread,并通過(guò)操作系統(tǒng)調(diào)度算法進(jìn)行調(diào)度(例如linux是CFS)。為了讓各個(gè)線(xiàn)程能夠平均利用CPU時(shí)間,python會(huì)計(jì)算當(dāng)前已執(zhí)行的微代碼數(shù)量,達(dá)到一定閾值后就強(qiáng)制釋放GIL。而這時(shí)也會(huì)觸發(fā)一次操作系統(tǒng)的線(xiàn)程調(diào)度(當(dāng)然是否真正進(jìn)行上下文切換由操作系統(tǒng)自主決定)。偽代碼

這種模式在只有一個(gè)CPU核心的情況下毫無(wú)問(wèn)題。任何一個(gè)線(xiàn)程被喚起時(shí)都能成功獲得到GIL(因?yàn)橹挥嗅尫帕薌IL才會(huì)引發(fā)線(xiàn)程調(diào)度)。但當(dāng)CPU有多個(gè)核心的時(shí)候,問(wèn)題就來(lái)了。從偽代碼可以看到,從release GIL到acquire GIL之間幾乎是沒(méi)有間隙的。所以當(dāng)其他在其他核心上的線(xiàn)程被喚醒時(shí),大部分情況下主線(xiàn)程已經(jīng)又再一次獲取到GIL了。這個(gè)時(shí)候被喚醒執(zhí)行的線(xiàn)程只能白白的浪費(fèi)CPU時(shí)間,看著另一個(gè)線(xiàn)程拿著GIL歡快的執(zhí)行著。然后達(dá)到切換時(shí)間后進(jìn)入待調(diào)度狀態(tài),再被喚醒,再等待,以此往復(fù)惡性循環(huán)。簡(jiǎn)單的總結(jié)下就是:Python的多線(xiàn)程在多核CPU上,只對(duì)于IO密集型計(jì)算產(chǎn)生正面效果;而當(dāng)有至少有一個(gè)CPU密集型線(xiàn)程存在,那么多線(xiàn)程效率會(huì)由于GIL而大幅下降。

4.線(xiàn)程池。修改 生成者消費(fèi)者 的代碼,不再是一個(gè)生產(chǎn)者和一個(gè)消費(fèi)者,而是可以有任意個(gè) 消費(fèi)者線(xiàn)程(一個(gè)線(xiàn)程池),每個(gè)線(xiàn)程可以在任意時(shí)刻處理或消耗任意多個(gè)產(chǎn)品

聲明:本文內(nèi)容及配圖由入駐作者撰寫(xiě)或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • python
    +關(guān)注

    關(guān)注

    56

    文章

    4799

    瀏覽量

    84817
  • 線(xiàn)程
    +關(guān)注

    關(guān)注

    0

    文章

    505

    瀏覽量

    19705
  • 解釋器
    +關(guān)注

    關(guān)注

    0

    文章

    103

    瀏覽量

    6543

原文標(biāo)題:python線(xiàn)程筆記

文章出處:【微信號(hào):magedu-Linux,微信公眾號(hào):馬哥Linux運(yùn)維】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

收藏 人收藏

    評(píng)論

    相關(guān)推薦

    進(jìn)程與線(xiàn)程的通俗解釋

    本帖最后由 檸檬守護(hù) 于 2016-8-10 17:42 編輯 進(jìn)程(process)和線(xiàn)程(thread)是操作系統(tǒng)的基本概念,但是它們比較抽象,不容易掌握。最近,我讀到一篇材料,發(fā)現(xiàn)有一個(gè)
    發(fā)表于 08-10 17:31

    好用的python解釋

    Python是一門(mén)解釋語(yǔ)言,代碼想運(yùn)行,必須通過(guò)解釋執(zhí)行,Python存在多種
    發(fā)表于 04-13 14:54

    Python線(xiàn)程編程原理

    Python線(xiàn)程類(lèi)似于同時(shí)執(zhí)行多個(gè)不同程序,但其執(zhí)行過(guò)程中和進(jìn)程還是有區(qū)別的,每個(gè)獨(dú)立的線(xiàn)程有一個(gè)程序運(yùn)行的入口、順序執(zhí)行序列和程序的出口,但是線(xiàn)程不能夠獨(dú)立執(zhí)行,必須依存在應(yīng)用程序
    發(fā)表于 11-22 14:01

    Python解釋的基本結(jié)構(gòu)

    簡(jiǎn)介Byterun是一個(gè)用Python實(shí)現(xiàn)的Python解釋。通過(guò)對(duì)Byterun的研究,我驚奇地發(fā)現(xiàn)Python
    發(fā)表于 09-16 06:42

    【干貨】趣味詳解 5 種 Python 線(xiàn)程

    切換的時(shí)機(jī)。需要我們值得留意的是,在Python基本數(shù)據(jù)類(lèi)型中l(wèi)ist、tuple、dict本身就是屬于線(xiàn)程安全的,所以如果有多個(gè)線(xiàn)程對(duì)這3種容器做操作時(shí),我們不必考慮線(xiàn)程安全問(wèn)題。
    發(fā)表于 12-08 11:10

    1.1 快速安裝 Python 解釋

    1.1【環(huán)境】快速安裝 Python 解釋Python 是一門(mén)解釋性腳本語(yǔ)言,因此要想讓你編寫(xiě)的代碼得以運(yùn)行,需要先安裝 CPython
    發(fā)表于 02-16 15:15

    使用Python多進(jìn)程的理由

    Python 是運(yùn)行在解釋中的語(yǔ)言,查找資料知道, python 中有一個(gè)全局( GI),在
    的頭像 發(fā)表于 04-04 16:50 ?1614次閱讀
    使用<b class='flag-5'>Python</b>多進(jìn)程的理由

    快速安裝 Python 解釋

    1.1【環(huán)境】快速安裝 Python 解釋 Python 是一門(mén)解釋性腳本語(yǔ)言,因此要想讓你編寫(xiě)的代碼得以運(yùn)行,需要先安裝 CPython
    的頭像 發(fā)表于 02-15 16:57 ?2258次閱讀
    快速安裝 <b class='flag-5'>Python</b> <b class='flag-5'>解釋</b><b class='flag-5'>器</b>

    Linux下線(xiàn)程間通訊--互斥

    互斥是一種簡(jiǎn)單的加鎖的方法來(lái)控制對(duì)共享資源的存取,當(dāng)多個(gè)線(xiàn)程訪(fǎng)問(wèn)公共資源時(shí),為了保證同一時(shí)刻只有一個(gè)線(xiàn)程獨(dú)占資源,就可以通過(guò)互斥加以限制,在一個(gè)時(shí)刻只能有一個(gè)
    的頭像 發(fā)表于 08-24 15:53 ?1979次閱讀
    Linux下<b class='flag-5'>線(xiàn)程</b>間通訊--互斥<b class='flag-5'>鎖</b>

    pycharm如何配置Python解釋

    剛學(xué)Python,你肯定遇到過(guò)這個(gè)問(wèn)題剛學(xué)Python時(shí),拿到一個(gè)Python項(xiàng)目,想用pycharm打開(kāi)運(yùn)行,pycharm界面卻顯示No Python Interpreter co
    的頭像 發(fā)表于 10-14 15:48 ?1.3w次閱讀
    pycharm如何配置<b class='flag-5'>Python</b><b class='flag-5'>解釋</b><b class='flag-5'>器</b>

    Python新提案:使全局解釋成為可選項(xiàng)

    解釋時(shí)進(jìn)行設(shè)置。但如果棄用該配置,會(huì)導(dǎo)致對(duì)解釋的構(gòu)建和運(yùn)行方式的深度侵入性更改,PEP 中也對(duì)此進(jìn)行了詳細(xì)介紹。
    的頭像 發(fā)表于 01-13 15:31 ?468次閱讀

    Python線(xiàn)程的使用

    最近常常需要處理大量的crash數(shù)據(jù),對(duì)這些數(shù)據(jù)進(jìn)行分析,在此之前需要將存量的數(shù)據(jù)導(dǎo)入自己的數(shù)據(jù)庫(kù),開(kāi)始一天一天的去導(dǎo),發(fā)現(xiàn)太慢了,后來(lái)嘗試通過(guò)python線(xiàn)程并行導(dǎo)入多天數(shù)據(jù),以此記錄對(duì)于Python
    的頭像 發(fā)表于 03-17 14:57 ?1105次閱讀

    如何安裝Python解釋

    安裝Python解釋是搭建Python編程環(huán)境的第一步。Python解釋
    的頭像 發(fā)表于 04-14 12:08 ?5397次閱讀

    GIL是什么?為什么需要GIL呢?

    全局解釋或GIL是一個(gè)互斥,它阻止多個(gè)本機(jī)線(xiàn)程同時(shí)執(zhí)行
    的頭像 發(fā)表于 09-20 15:44 ?1128次閱讀
    GIL<b class='flag-5'>鎖</b>是什么?為什么需要GIL<b class='flag-5'>鎖</b>呢?

    python中5種線(xiàn)程盤(pán)點(diǎn)

    線(xiàn)程安全是多線(xiàn)程或多進(jìn)程編程中的一個(gè)概念,在擁有共享數(shù)據(jù)的多條線(xiàn)程并行執(zhí)行的程序中,線(xiàn)程安全的代碼會(huì)通過(guò)同步機(jī)制保證各個(gè)線(xiàn)程都可以正常且正確
    發(fā)表于 03-07 11:08 ?1622次閱讀
    <b class='flag-5'>python</b>中5種<b class='flag-5'>線(xiàn)程</b><b class='flag-5'>鎖</b>盤(pán)點(diǎn)
    主站蜘蛛池模板: 黄色网址在线播放| 天天久久影视色香综合网| 麻豆成人啪啪色婷婷久久| xx在线观看| 日韩 国产 欧美视频二区| 大胸美女被C得嗷嗷叫动态图| 收集最新中文国产中文字幕| 麻豆免费版| 精品久久久噜噜噜久久久app| 国产成人精品综合在线观看| 99热视频这里只有久久精品| 无人区日本电影在线观看高清 | seyeye在清在线| 羞羞漫画免费漫画页面在线看漫画秋蝉| 蜜桃人妻无码AV天堂三区 | 老头狠狠挺进小莹体内视频| 国产成人99久久亚洲综合精品| 99九九免费热在线精品| 无人区乱码1区2区3区网站| 人人澡人人爽人人精品| 好大好硬好爽好深好硬视频| 99久久精品国产亚洲AV| 亚洲免费人成 久久| 午夜一个人在线观看完整版| 三级叫床震大尺度视频| 日本欧美高清一区二区视频| 男插女高潮一区二区| 老师你狠狂| 麻豆XXXX乱女少妇精品-百度| 久久久无码精品亚洲日韩按摩| 久久99re2在线视频精品| 超碰免费视频部落格| FERRCHINA内入内射| JIZZ19学生第一次| JAVASCRIPTJAVA水多多| FREECHINESE东北女人真爽| bbw videos 欧美老妇| 拔萝卜在线高清观看视频| 成年色黄APP下载| 国产99精品在线观看| freevideoshd|