Python多執行緒之執行緒建立和終止
python主要是通過thread和threading這兩個模組來實現多執行緒支援。python的thread模組是比較底層的模組,python的threading模組是對thread做了一些封裝,可以更加方便的被使用。但是python(cpython)由於GIL的存在無法使用threading充分利用CPU資源,如果想充分發揮多核CPU的計算能力需要使用multiprocessing模組(Windows下使用會有諸多問題)。
如果在對執行緒應用有較高的要求時可以考慮使用Stackless Python來完成。Stackless Python是Python的一個修改版本,對多執行緒程式設計有更好的支援,提供了對微執行緒的支援。微執行緒是輕量級的執行緒,在多個執行緒間切換所需的時間更多,佔用資源也更少。
通過threading模組建立新的執行緒有兩種方法:一種是通過threading.Thread(Target=executable Method)-即傳遞給Thread物件一個可執行方法(或物件);第二種是繼承threading.Thread定義子類並重寫run()方法。第二種方法中,唯一必須重寫的方法是run(),可根據需要決定是否重寫__init__()。值得注意的是,若要重寫__init__(),父類的__init__()必須要在函式第一行呼叫,否則會觸發錯誤“AssertionError: Thread.__init__() not called”
Python threading模組不同於其他語言之處在於它沒有提供執行緒的終止方法,通過Python threading.Thread()啟動的執行緒彼此是獨立的,若線上程A中啟動了執行緒B,那麼A、B是彼此獨立執行的執行緒。若想終止執行緒A的同時強力終止執行緒B,一個簡單的方法是通過線上程A中呼叫B.setDaemon(True)實現。但這樣帶來的問題是:執行緒B中的資源(開啟的檔案、資料傳輸等)可能會沒有正確的釋放。所以setDaemon()並非一個好方法,更為妥當的方式是通過Event機制。下面這段程式體現了setDaemon()和Event機制終止子執行緒的區別。
import threading import time class mythread(threading.Thread): def __init__(self,stopevt = None,File=None,name = 'subthread',Type ='event'): threading.Thread.__init__(self) self.stopevt = stopevt self.name = name self.File = File self.Type = Type def Eventrun(self): while not self.stopevt.isSet(): print self.name +' alive\n' time.sleep(2) if self.File: print 'close opened file in '+self.name+'\n' self.File.close() print self.name +' stoped\n' def Daemonrun(self): D = mythreadDaemon(self.File) D.setDaemon(True) while not self.stopevt.isSet(): print self.name +' alive\n' time.sleep(2) print self.name +' stoped\n' def run(self): if self.Type == 'event': self.Eventrun() else: self.Daemonrun() class mythreadDaemon(threading.Thread): def __init__(self,File=None,name = 'Daemonthread'): threading.Thread.__init__(self) self.name = name self.File = File def run(self): while True: print self.name +' alive\n' time.sleep(2) if self.File: print 'close opened file in '+self.name+'\n' self.File.close() print self.name +' stoped\n' def evtstop(): stopevt = threading.Event() FileA = open('testA.txt','w') FileB = open('testB.txt','w') A = mythread(stopevt,FileA,'subthreadA') B = mythread(stopevt,FileB,'subthreadB') print repr(threading.currentThread())+'alive\n' print FileA.name + ' closed? '+repr(FileA.closed)+'\n' print FileB.name + ' closed? '+repr(FileB.closed)+'\n' A.start() B.start() time.sleep(1) print repr(threading.currentThread())+'send stop signal\n' stopevt.set() A.join() B.join() print repr(threading.currentThread())+'stoped\n' print 'after A stoped, '+FileA.name + ' closed? '+repr(FileA.closed)+'\n' print 'after A stoped, '+FileB.name + ' closed? '+repr(FileB.closed)+'\n' def daemonstop(): stopevt = threading.Event() FileA = open('testA.txt','r') A = mythread(stopevt,FileA,'subthreadA',Type = 'Daemon') print repr(threading.currentThread())+'alive\n' print FileA.name + ' closed? '+repr(FileA.closed)+'\n' A.start() time.sleep(1) stopevt.set() A.join() print repr(threading.currentThread())+'stoped\n' print 'after A stoped, '+FileA.name + ' closed? '+repr(FileA.closed)+'\n' if not FileA.closed: print 'You see the differents, the resource in subthread may not released with setDaemon()' FileA.close() if __name__ =='__main__': print '-------stop subthread example with Event:----------\n' evtstop() print '-------Daemon stop subthread example :----------\n' daemonstop()
執行結果是:
-------stop subthread example with Event:----------
<_MainThread(MainThread, started 2436)>alive
testA.txt closed? False
testB.txt closed? False
subthreadA alive
subthreadB alive
<_MainThread(MainThread, started 2436)>send stop signal
close opened file in subthreadA
close opened file in subthreadB
subthreadA stoped
subthreadB stoped
<_MainThread(MainThread, started 2436)>stoped
after A stoped, testA.txt closed? True
after A stoped, testB.txt closed? True
-------Daemon stop subthread example :----------
<_MainThread(MainThread, started 2436)>alive
testA.txt closed? False
subthreadA alive
subthreadA stoped
<_MainThread(MainThread, started 2436)>stoped
after A stoped, testA.txt closed? False
You see the differents, the resource in subthread may not released with setDaemon()