Python多線程編程

來源:互聯網
上載者:User

線程與進程的不同之處在於,它們共用狀態、記憶體和資源。對於線程來說,這個簡單的區別既是它的優勢,又是它的缺點。一方面,線程是輕量級的,並且相互之間易於通訊,但另一方面,它們也帶來了包括死結、競爭條件和高複雜性在內的各種問題。幸運的是,由於 GIL 和隊列模組,與採用其他的語言相比,採用 Python 語言線上程實現的複雜性上要低得多。

全域解譯器鎖 (Global Interpretor Lock) 說明 Python 解譯器並不是安全執行緒的。當前線程必須持有全域鎖,以便對 Python 對象進行安全地訪問。因為只有一個線程可以獲得 Python 對象/C API,所以解譯器每經過 100 個位元組碼的指令,就有規律地釋放和重新獲得鎖。解譯器對線程切換進行檢查的頻率可以通過 sys.setcheckinterval() 函數來進行控制。

需要說明的是,因為 GIL,CPU 受限的應用程式將無法從線程的使用中受益。使用 Python 時,建議使用進程,或者混合建立進程和線程。

Python中如果要使用線程的話,python的lib中提供了兩種方式。一種是函數式,一種是用類來封裝的線程對象。

關於多線程編程的其他知識例如互斥、訊號量、臨界區等請參考python的文檔及相關資料。

下面來看一下使用python進行多線程編程的兩個方式


函數式

調用thread模組中的start_new_thread()函數來產生新的線程,範例程式碼如下:

#!/usr/bin/env python
# encoding: utf8

import time
import thread

def timer(no, interval):
""""""
print 'Thread :(%d) Time:%s'%(no,time.ctime())
time.sleep(interval)
print 'Thread :(%d) End.'%no

def test():
""""""
thread.start_new_thread(timer,(1,1))
thread.start_new_thread(timer,(2,3))
time.sleep(5)

if __name__ == '__main__':
test()

這個是thread.start_new_thread(function,args[,kwargs])函數原型,其中function參數是你將要調用的線程函數;args是講傳遞給你的線程函數的參數,他必須是個tuple類型;而kwargs是可選的參數。 線程的結束一般依靠線程函數的自然結束;也可以線上程函數中調用thread.exit(),他拋出SystemExit exception,達到退出線程的目的。


繼承式

通過調用threading模組繼承threading.Thread類來封裝一個線程對象。範例程式碼如下:

#!/usr/bin/env python
# encoding: utf8
import threading
import time
class timer(threading.Thread): #我的timer類繼承自threading.Thread類
def __init__(self,no,interval):
#在我重寫__init__方法的時候要記得調用基類的__init__方法
threading.Thread.__init__(self)
self.no=no
self.interval=interval

def run(self): #重寫run()方法,把自己的線程函數的代碼放到這裡
print 'Thread Object %s (%d), Time:%s'%(self.getName(),self.no,time.ctime())
time.sleep(self.interval)

def test():
threadone=timer(1,1) #產生2個線程對象
threadtwo=timer(2,3)
threadone.start() #通過調用線程對象的.start()方法來啟用線程
threadtwo.start()

if __name__=='__main__':
test()

 

多線程分析

getName()是threading.Thread類的一個方法,用來獲得這個線程對象的name。還有一個方法setName()當然就是來設定這個線程對象的name的了。

  1. 建立一個線程,首先就要先建立一個線程對象:threadone=timer(1,1) 一個線程對象被建立後,他就處於“born”(誕生狀態)
  2. 啟動線程,調用線程對象的start()方法即可:mythread1.start() 現線上程就處於“ready”狀態或者也稱為“runnable”狀態。
  3. 線程在未分到CPU時間片處理時處於“sleep”狀態
  4. 一般來說當線程對象的run方法執行結束或者在執行中拋出異常的話,那麼這個線程就會結束了,處於“dead”狀態。系統會自動對“dead”狀態線程進行清理。
  5. 如果一個線程t1在執行的過程中需要等待另一個線程t2執行結束後才能啟動並執行話那就可以在t1中調用t2的join()方法
  6. 如果一個進程的主線程運行完畢而子線程還在執行的話,那麼進程就不會退出,直到所有子線程結束為止。

如何讓主線程結束的時候其他子線程也退出呢?使用線程對象的setDaemon()方法,參數為bool型。True的話就代表你要聽話,我老大(主線程)扯呼,你也要跟著撤,不能拖後腿。如果是False的話就不用那麼聽話了,老大允許你們將在外軍命有所不受的。需要注意的是setDaemon()方法必須線上程對象沒有調用start()方法之前調用,否則沒效果

t1 = mythread('t1')
print t1.getName(),t1.isDaemon()
t1.setDaemon(True)
print t1.getName(),t1.isDaemon()
t1.start()
print 'main thread exit'

 

獲得與線程有關的資訊

a.獲得當前正在啟動並執行線程的引用

 running = threading.currentThread()

b.獲得當前所有使用中的物件(即run方法開始但是未終止的任何線程)的一個列表

 threadlist = threading.enumerate()

c.獲得這個列表的長度

threadcount = threading.activeCount()

d.查看一個線程對象的狀態調用這個線程對象的isAlive()方法,返回1代表處於“runnable”狀態且沒有“dead”

threadflag = threading.isAlive()

相關文章

聯繫我們

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