python多線程用法實例詳解
來源:易賢網(wǎng) 閱讀:1049 次 日期:2015-01-16 13:58:30
溫馨提示:易賢網(wǎng)小編為您整理了“python多線程用法實例詳解”,方便廣大網(wǎng)友查閱!

本文實例分析了python多線程用法。分享給大家供大家參考。具體如下:

今天在學習嘗試學習python多線程的時候,突然發(fā)現(xiàn)自己一直對super的用法不是很清楚,所以先總結(jié)一些遇到的問題。當我嘗試編寫下面的代碼的時候:

復制代碼 代碼如下:class A():

def __init__( self ):

print "A"

class B( A ):

def __init__( self ):

super( B, self ).__init__( )

# A.__init__( self )

print "B"

b = B()

出現(xiàn):

super( B, self ).__init__()

TypeError: must be type, not classobj

最后發(fā)現(xiàn)原來是python中的新式類的問題,也就是A必須是新式類。解決方法如下兩種:

(1)

復制代碼 代碼如下:class A( object ):

def __init__( self ):

print "A"

class B( A ):

def __init__( self ):

super( B, self ).__init__( )

# A.__init__( self ) ##這條語句是舊式的,存在潛在的問題,應該避免使用

print "B"

b = B()

(2)

復制代碼 代碼如下:__metaclass__=type

class A():

def __init__( self ):

print "A"

class B( A ):

def __init__( self ):

super( B, self ).__init__( )

# A.__init__( self ) ##這條語句是舊式的,存在潛在的問題,應該避免使用

print "B"

b = B()

注意:如果在super( B, self ).__init__( )

語句中添加self,也就是super( B, self ).__init__( self ),會出現(xiàn)如下的錯誤:

super( B, self ).__init__( self )

TypeError: __init__() takes exactly 1 argument (2 given)

以上只是一點點本人的心得筆記,呵呵。

復制代碼 代碼如下:import threading, time

class myThread( threading.Thread ):

def __init__( self, threadname = "" ):

#threading.Thread.__init__( self, name = threadname )

super( myThread, self ).__init__( name = threadname )

def run( self ):

print "starting====", self.name, time.ctime()

time.sleep( 5 )

print "end====", self.name, time.ctime(),

m = myThread( "m" )

n = myThread( "n" )

m.start()

n.start()

輸出的結(jié)果:

starting==== m Mon Aug 08 21:55:41 2011

starting==== n Mon Aug 08 21:55:41 2011

如果一個進程的主線程運行完畢而子線程還在執(zhí)行的話,那么進程就不會退出,直到所有子線程結(jié)束為止。比如下面的例子:

復制代碼 代碼如下:import threading, time

class myThread( threading.Thread ):

def __init__( self, threadname = "" ):

#threading.Thread.__init__( self, name = threadname )

super( myThread, self ).__init__( name = threadname )

def run( self ):

print "starting====", self.name, time.ctime()

time.sleep( 5 )

print "end====", self.name, time.ctime(),

m = myThread( "m" )

m.start()

print "main end"

print

輸出的結(jié)果為:

starting==== m Mon Aug 08 22:01:06 2011

main end

end==== m Mon Aug 08 22:01:11 2011

也就是主進程結(jié)束之后,子進程還沒有結(jié)束

如果我們想在主進程結(jié)束的時候,子進程也結(jié)束的話,我們就應該使用setDaemon()函數(shù)。

實例如下:

復制代碼 代碼如下:import threading, time

class myThread( threading.Thread ):

def __init__( self, threadname = "" ):

#threading.Thread.__init__( self, name = threadname )

super( myThread, self ).__init__( name = threadname )

def run( self ):

print "starting====", self.name, time.ctime()

time.sleep( 5 )

print "end====", self.name, time.ctime(),

m = myThread( "m" )

m.setDaemon( True )

m.start()

print "main end"

print

輸出的結(jié)果為:starting====main end m Mon Aug 08 22:02:58 2011

可以看出,并沒有打印出子進程m結(jié)束的時候本應該打印的“end===…”

簡單的線程同步

個執(zhí)行線程經(jīng)常要共享數(shù)據(jù),如果僅僅讀取共享數(shù)據(jù)還好,但是如果多個線程要修改共享數(shù)據(jù)的話就可能出現(xiàn)無法預料的結(jié)果。

假如兩個線程對象t1和t2都要對數(shù)值num=0進行增1運算,那么t1和t2都各對num修改10次的話,那么num最終的結(jié)果應該為20。但是如果當t1取得num的值時(假如此時num為0),系統(tǒng)把t1調(diào)度為“sleeping”狀態(tài),而此時t2轉(zhuǎn)換為“running”狀態(tài),此時t2獲得的num的值也為0,然后他把num+1的值1賦給num。系統(tǒng)又把t2轉(zhuǎn)化為“sleeping”狀態(tài),t1為“running”狀態(tài),由于t1已經(jīng)得到num值為0,所以他也把num+1的值賦給了num為1。本來是2次增1運行,結(jié)果卻是num只增了1次。類似這樣的情況在多線程同時執(zhí)行的時候是有可能發(fā)生的。所以為了防止這類情況的出現(xiàn)就要使用線程同步機制。

最簡單的同步機制就是“鎖”

鎖對象用threading.RLock類創(chuàng)建

復制代碼 代碼如下:mylock = threading.RLock()

如何使用鎖來同步線程呢?線程可以使用鎖的acquire() (獲得)方法,這樣鎖就進入“l(fā)ocked”狀態(tài)。每次只有一個線程可以獲得鎖。如果當另一個線程試圖獲得這個鎖的時候,就會被系統(tǒng)變?yōu)椤癰locked”狀態(tài),直到那個擁有鎖的線程調(diào)用鎖的release() (釋放)方法,這樣鎖就會進入“unlocked”狀態(tài)。“blocked”狀態(tài)的線程就會收到一個通知,并有權(quán)利獲得鎖。如果多個線程處于“blocked”狀態(tài),所有線程都會先解除“blocked”狀態(tài),然后系統(tǒng)選擇一個線程來獲得鎖,其他的線程繼續(xù)沉默(“blocked”)。

復制代碼 代碼如下:import threading

mylock = threading.RLock()

class mythread(threading.Thread)

...

def run(self ...):

... #此處 不可以 放置修改共享數(shù)據(jù)的代碼

mylock.acquire()

... #此處 可以 放置修改共享數(shù)據(jù)的代碼

mylock.release()

... #此處 不可以 放置修改共享數(shù)據(jù)的代碼

我們把修改共享數(shù)據(jù)的代碼稱為“臨界區(qū)”,必須將所有“臨界區(qū)”都封閉在同一鎖對象的acquire()和release()方法調(diào)用之間。

鎖只能提供最基本的同步級別。有時需要更復雜的線程同步,例如只在發(fā)生某些事件時才訪問一個臨界區(qū)(例如當某個數(shù)值改變時)。這就要使用“條件變量”。

條件變量用threading.Condition類創(chuàng)建

復制代碼 代碼如下:mycondition = threading.Condition()

條件變量是如何工作的呢?首先一個線程成功獲得一個條件變量后,調(diào)用此條件變量的wait()方法會導致這個線程釋放這個鎖,并進入“blocked”狀態(tài),直到另一個線程調(diào)用同一個條件變量的notify()方法來喚醒那個進入“blocked”狀態(tài)的線程。如果調(diào)用這個條件變量的notifyAll()方法的話就會喚醒所有的在等待的線程。

如果程序或者線程永遠處于“blocked”狀態(tài)的話,就會發(fā)生死鎖。所以如果使用了鎖、條件變量等同步機制的話,一定要注意仔細檢查,防止死鎖情況的發(fā)生。對于可能產(chǎn)生異常的臨界區(qū)要使用異常處理機制中的finally子句來保證釋放鎖。等待一個條件變量的線程必須用notify()方法顯式的喚醒,否則就永遠沉默。保證每一個wait()方法調(diào)用都有一個相對應的notify()調(diào)用,當然也可以調(diào)用notifyAll()方法以防萬一。

同步隊列

我們經(jīng)常會采用生產(chǎn)者/消費者關系的兩個線程來處理一個共享緩沖區(qū)的數(shù)據(jù)。例如一個生產(chǎn)者線程接受用戶數(shù)據(jù)放入一個共享緩沖區(qū)里,等待一個消費者線程對數(shù)據(jù)取出處理。但是如果緩沖區(qū)的太小而生產(chǎn)者和消費者兩個異步線程的速度不同時,容易出現(xiàn)一個線程等待另一個情況。為了盡可能的縮短共享資源并以相同速度工作的各線程的等待時間,我們可以使用一個“隊列”來提供額外的緩沖區(qū)。

創(chuàng)建一個“隊列”對象,可以使用如下代碼:

復制代碼 代碼如下:import Queue

myqueue = Queue.Queue(maxsize = 10)

Queue.Queue類即是一個隊列的同步實現(xiàn)。隊列長度可為無限或者有限。可通過Queue的構(gòu)造函數(shù)的可選參數(shù)maxsize來設定隊列長度。如果maxsize小于1就表示隊列長度無限。

將一個值放入隊列中:

myqueue.put(10)

調(diào)用隊列對象的put()方法在隊尾插入一個項目。put()有兩個參數(shù),第一個item為必需的,為插入項目的值;第二個block為可選參數(shù),默認為1。如果隊列當前為空且block為1,put()方法就使調(diào)用線程暫停,直到空出一個數(shù)據(jù)單元。如果block為0,put方法將引發(fā)Full異常。

將一個值從隊列中取出:

myqueue.get()

調(diào)用隊列對象的get()方法從隊頭刪除并返回一個項目??蛇x參數(shù)為block,默認為1。如果隊列為空且block為1,get()就使調(diào)用線程暫停,直至有項目可用。如果block為0,隊列將引發(fā)Empty異常。

我們用一個例子來展示如何使用Queue:

復制代碼 代碼如下:# queue_example.py

from Queue import Queue

import threading

import random

import time

# Producer thread

class Producer( threading.Thread ):

def __init__( self, threadname, queue ):

threading.Thread.__init__( self, name = threadname )

self.sharedata = queue

def run( self ):

for i in range( 20 ):

print self.getName(), 'adding', i, 'to queue'

self.sharedata.put( i )

time.sleep( random.randrange( 10 ) / 10.0 )

print self.getName(), 'Finished'

# Consumer thread

class Consumer( threading.Thread ):

def __init__( self, threadname, queue ):

threading.Thread.__init__( self, name = threadname )

self.sharedata = queue

def run( self ):

for i in range( 20 ):

print self.getName(), 'got a value:', self.sharedata.get()

time.sleep( random.randrange( 10 ) / 10.0 )

print self.getName(), 'Finished'

# Main thread

def main():

queue = Queue()

producer = Producer( 'Producer', queue )

consumer = Consumer( 'Consumer', queue )

print 'Starting threads ...'

producer.start()

consumer.start()

producer.join()

consumer.join()

print 'All threads have terminated.'

if __name__ == '__main__':

main()

程序輸出的結(jié)果為:

Starting threads ...

Producer adding 0 to queue

Consumer got a value: 0

Producer Finished

Producer adding 1 to queue

Producer Finished

Producer adding 2 to queue

Consumer Finished

Consumer got a value: 1

Consumer Finished

Consumer got a value: 2

Consumer Finished

Consumer got a value: Producer Finished

Producer adding 3 to queue

3

Consumer Finished

Consumer got a value: Producer Finished

Producer adding 4 to queue

4

ConsumerProducer Finished

ConsumerFinished

got a value:Producer adding 5 to queue

5

Consumer Finished

Consumer got a value: Producer Finished

Producer adding 6 to queue

Producer Finished

Producer adding 7 to queue

6

Consumer Finished

Consumer got a value: 7

Producer Finished

Producer adding 8 to queue

Producer Finished

Producer adding 9 to queue

Consumer Finished

Consumer got a value: 8

ConsumerProducer FinishedFinished

ConsumerProducer got a value:adding 109

to queue

Producer Finished

Producer adding 11 to queue

Producer Finished

Producer adding 12 to queue

ConsumerProducer FinishedFinished

ConsumerProducer got a value:adding 1310

to queue

Producer Finished

Producer adding 14 to queue

Consumer Finished

Consumer got a value: 11

Producer Finished

Producer adding 15 to queue

Producer Finished

Producer adding 16 to queue

Producer Finished

Producer adding 17 to queue

Producer Finished

Producer adding 18 to queue

Consumer Finished

Consumer got a value: 12

Producer Finished

Producer adding 19 to queue

Producer Finished

Consumer Finished

Consumer got a value: 13

Consumer Finished

Consumer got a value: 14

Consumer Finished

Consumer got a value: 15

Consumer Finished

Consumer got a value: 16

Consumer Finished

Consumer got a value: 17

Consumer Finished

Consumer got a value: 18

Consumer Finished

Consumer got a value: 19

Consumer Finished

All threads have terminated.

希望本文所述對大家的Python程序設計有所幫助。

更多信息請查看IT技術(shù)專欄

更多信息請查看腳本欄目
易賢網(wǎng)手機網(wǎng)站地址:python多線程用法實例詳解

2025國考·省考課程試聽報名

  • 報班類型
  • 姓名
  • 手機號
  • 驗證碼
關于我們 | 聯(lián)系我們 | 人才招聘 | 網(wǎng)站聲明 | 網(wǎng)站幫助 | 非正式的簡要咨詢 | 簡要咨詢須知 | 新媒體/短視頻平臺 | 手機站點 | 投訴建議
工業(yè)和信息化部備案號:滇ICP備2023014141號-1 云南省教育廳備案號:云教ICP備0901021 滇公網(wǎng)安備53010202001879號 人力資源服務許可證:(云)人服證字(2023)第0102001523號
聯(lián)系電話:0871-65099533/13759567129 獲取招聘考試信息及咨詢關注公眾號:hfpxwx
咨詢QQ:1093837350(9:00—18:00)版權(quán)所有:易賢網(wǎng)