python多線程編程1

來源:互聯網
上載者:User
多線程編程必須理解的一些基本概念,適用於所有程式設計語言。內容:

並髮式編程

多任務作業系統

多線程vs多進程

安全執行緒

線程的生命週期

線程的類型

並髮式編程

不同的編程範式對軟體有不同的視角。並髮式編程將軟體看做任務和資源的組合——任務之間競爭和共用資源,當資源滿足時執行任務,否則等待資源。

並髮式編程使得軟體易於理解和重用,在某些情境能夠極大提高效能。

多任務作業系統

要實現並發,首先需要作業系統的支援。現在的作業系統大部分都是多任務作業系統,可以“同時”執行多個任務。

多任務可以在進程或線程的層面執行。

進程是指一個記憶體中啟動並執行應用程式,每個進程都有自己獨立的一塊記憶體空間。多任務作業系統可以“並發”執行這些進程。

線程是指進程中亂序、多次執行的代碼塊,多個線程可以“同時”運行,所以認為多個線程是“並發”的。多線程的目的是為了最大限度的利用CPU資源。比如一個JVM進程中,所有的程式碼都以線程的方式運行。

這裡面的“同時”、“並發”只是一種宏觀上的感受,實際上從微觀層面看只是進程/線程的輪換執行,只不過切換的時間非常短,所以產生了“並行”的感覺。

多線程vs多進程

作業系統會為每個進程分配不同的記憶體塊,而多個線程共用進程的記憶體塊。這帶來最直接的不同就是建立線程的開銷遠小於建立進程的開銷。

同時,由於記憶體塊不同,所以進程之間的通訊相對困難。需要採用pipe/named pipe,signal, message queue, shared memory,socket等手段;而線程間的通訊簡單快速,就是共用進程內的全域變數。

但是,進程的調度由作業系統負責,線程的調度就需要我們自己來考慮,避免死結,饑餓,活鎖,資源枯竭等情況的發生,這會增加一定的複雜度。而且,由於線程之間共用記憶體,我們還需要考慮執行緒安全性的問題。

安全執行緒

以為線程間共用進程中的全域變數,所以當其他線程改變了共用的變數時,可能會對本線程產生影響。所謂安全執行緒的約束是指一個函數被多個並發線程反覆調用時,要一直產生正確的結果。要保證安全執行緒,主要是通過加鎖的方式保證共用變數的正確訪問。

比安全執行緒更嚴格的約束是"可重新進入性",即函數在一個線程內執行的過程中被暫停,接下來又在另一個線程內被調用,之後在返回原線程繼續執行。在整個過程中都能保證正確執行。保證可重新進入性,通常通過製作全域變數的本地拷貝來實現。

線程的生命週期

所謂的xx生命週期,其實就是某對象的包含產生和銷毀的一張狀態圖。線程的生命週期如所示:

各狀態的說明如下:

New建立。新建立的線程經過初始化後,進入Runnable狀態。

Runnable就緒。等待線程調度。調度後進入運行狀態。

Running運行。

Blocked阻塞。暫停運行,解除阻塞後進入Runnable狀態重新等待調度。

Dead消亡。線程方法執行完畢返回或者異常終止。

可能有3種情況從Running進入Blocked:

同步:線程中擷取同步鎖,但是資源已經被其他線程鎖定時,進入Locked狀態,直到該資源可擷取(擷取的順序由Lock隊列控制)

睡眠:線程運行sleep()或join()方法後,線程進入Sleeping狀態。區別在於sleep等待固定的時間,而join是等待子線程執行完。當然join也可以指定一個“逾時時間”。從語義上來說,如果兩個線程a,b, 在a中調用b.join(),相當於合并(join)成一個線程。最常見的情況是在主線程中join所有的子線程。

等待:線程中執行wait()方法後,線程進入Waiting狀態,等待其他線程的通知(notify)。

線程的類型

主線程:當一個程式啟動時,就有一個進程被作業系統(OS)建立,與此同時一個線程也立刻運行,該線程通常叫做程式的主線程(Main Thread)。每個進程至少都有一個主線程,主線程通常最後關閉。

子線程:在程式中建立的其他線程,相對於主線程來說就是這個主線程的子線程。

守護線程:daemon thread,對線程的一種標識。守護線程為其他線程提供服務,如JVM的記憶體回收線程。當剩下的全是守護線程時,進程退出。

前台線程:相對於守護線程的其他線程稱為前台線程。


python對多線程的支援

虛擬機器層面

Python虛擬機器使用GIL(Global Interpreter Lock,全域解譯器鎖)來互斥線程對共用資源的訪問,暫時無法利用多處理器的優勢。

語言層面

在語言層面,Python對多線程提供了很好的支援,Python中多線程相關的模組包括:thread,threading,Queue。可以方便地支援建立線程、互斥鎖、訊號量、同步等特性。

thread:多線程的底層支援模組,一般不建議使用。

threading:對thread進行了封裝,將一些線程的操作對象化,提供下列類:

Thread 線程類

Timer與Thread類似,但要等待一段時間後才開始運行

Lock 鎖原語

RLock 可重新進入鎖。使單線程可以再次獲得已經獲得的鎖

Condition 條件變數,能讓一個線程停下來,等待其他線程滿足某個“條件”

Event 通用的條件變數。多個線程可以等待某個事件發生,在事件發生後,所有的線程都被啟用

Semaphore為等待鎖的線程提供一個類似“等候室”的結構

BoundedSemaphore 與semaphore類似,但不允許超過初始值

Queue:實現了多生產者(Producer)、多消費者(Consumer)的隊列,支援鎖原語,能夠在多個線程之間提供很好的同步支援。提供的類:

Queue隊列

LifoQueue後入先出(LIFO)隊列

PriorityQueue 優先隊列

其中Thread類是你主要的線程類,可以建立進程執行個體。該類提供的函數包括:

getName(self) 返回線程的名字

isAlive(self) 布爾標誌,表示這個線程是否還在運行中

isDaemon(self) 返回線程的daemon標誌

join(self, timeout=None) 程式掛起,直到線程結束,如果給出timeout,則最多阻塞timeout秒

run(self) 定義線程的功能函數

setDaemon(self, daemonic) 把線程的daemon標誌設為daemonic

setName(self, name) 設定線程的名字

start(self) 開始線程執行

第三方支援

如果你特別在意效能,還可以考慮一些“微線程”的實現:

Stackless Python:Python的一個增強版本,提供了對微線程的支援。微線程是輕量級的線程,在多個線程間切換所需的時間更多,佔用資源也更少。

greenlet:是 Stackless 的副產品,其將微線程稱為 “tasklet” 。tasklet運行在偽並發中,使用channel進行同步資料交換。而”greenlet”是更加原始的微線程的概念,沒有調度。你可以自己構造微線程的調度器,也可以使用greenlet實現進階的控制流程。

下一節,將開始用python建立和啟動線程。

  • 聯繫我們

    該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.