多線程技術python
python經過兩個標準庫thread和threading提供對線程的支持。thread提供了低級別的,原始的線程以及一個簡單的鎖。threading基於Java的線程模型設計。數組
1.threading模塊
應該避免使用thread模塊,緣由是它不支持守護線程。當主線程退出時,全部的子線程無論他們是否還在工做,都會被強行退出。有時候並不但願出現此種行爲,所以就引入了守護線程的概念。threading模塊支持守護線程,因此,咱們直接使用threading來改進上述的例子。多線程
#threads.py
#coding:utf-8
from time import sleep,ctime
import threading
#聽音樂任務
def music(func,loop):
for i in range(loop):
print('i was listening to %s! %s' % (func,ctime()))
sleep(2)
#看電影任務
def movies(func,loop):
for i in range(loop):
print('i was watch the %s!%s' %(func,ctime()))
sleep(5)
#建立線程數組
threads=[]
#建立線程t1,並添加到線程數組
t1=threading.Thread(target=music,args=(u'愛情買賣',2))
threads.append(t1)
#建立線程t2,並添加到線程數組
t2=threading.Thread(target=movies,args=(u'阿凡達',2))
threads.append(t2)
if __name__=="__main__":
#啓動線程
for t in threads:
t.start()
#守護線程
for t in threads:
t.join()
print ('all end %s' %ctime())
執行以後,結果以下圖所示:app
-import threading:引入線程模塊
-threads=[]:建立線程數組,用於裝載線程。
-threading.Thread():經過調用threading模塊的Thread()方法來建立線程。函數
經過for循環遍歷threads數組中所裝載的線程,start()開始線程活動,join()等待線程終止。若是不使用join()方法對每一個線程作等待終止,那麼在線程運行的過程當中可能會去執行最後的打印「all end…」
代碼分析:
從上面的運行結果能夠看出,兩個子線程(music/movie)同時啓動於46分09秒,直到全部線程結束於46分19秒,總耗時10秒,movie的兩次電影循環共須要10秒,music的歌曲循環須要4秒,從執行結果看出兩個線程達到了並行工做。oop
2.優化線程的建立
上述例子中,每建立一個線程都須要建立一個t(t1,t2,……),當建立的線程較多時,這樣不方便,所以下面例子將做出改進。優化
#player.py
#coding:utf-8
from time import sleep,ctime
import threading
#建立超級播放器
def super_player(file_,time):
for i in range(2):
print 'Start playing:%s! %s' %(file_,ctime())
sleep(time)
#播放的文件與播放時長
lists={u'愛情買賣.mp3':3,u'阿凡達.mp4':5,u'我和你.mp3':4}
threads=[]
files=range(len(lists))
#建立線程
for file_,time in lists.items():
t=threading.Thread(target=super_player,args=(file_,time))
threads.append(t)
if __name__=="__main__":
#啓動線程
for t in files:
threads[t].start()
for t in files:
threads[t].join()
print 'all end"%s' %ctime()
執行以後,結果以下圖所示:spa
此例中,對播放器的功能也作了加強,首先,建立了一個super_player()函數,這個函數能夠接收播放文件和播放時長,能夠播聽任何文件。線程
而後,咱們建立了一個lists字典用於存放播放文件名與時長,經過for循環讀取字典,並調用super_player()函數建立字典,接着將建立的字典都追加到threads數組中。設計
3.建立線程類
除直接使用python所提供的線程類外,還能夠根據需求自定義本身的線程類。
#mythread.py
#coding:utf-8
from time import sleep,ctime
import threading
#建立線程類
class MyThreads(threading.Thread):
def __init__(self,func,args,name=''):
threading.Thread.__init__(self)
self.func=func
self.args=args
self.name=name
def run(self):
self.func(*self.args)
def super_play(file_,time):
for i in range(2):
print('Start playing:%s! %s' %(file_,ctime()))
sleep(time)
lists={u'愛情買賣.mp3':3,u'阿凡達.mp4':5,u'我和你.mp3':4}
threads=[]
files=range(len(lists))
for file_,time in lists.items():
t=MyThreads(super_play,(file_,time),super_play.__name__)
threads.append(t)
if __name__=='__main__':
#啓動線程
for i in files:
threads[i].start()
for i in files:
threads[i].join()
print'all end:%s' %ctime()
執行以後,結果以下圖所示:
MyThreads(threading.Thread) 建立MyThread類,用於繼承threading.Thread類 __init__()類的初始化方法對func、args、name等參數進行初始化。
在python2中,apply(func[,args[,kwargs]])函數的做用是當函數參數已經存在於一個元組或字典中,apply()間接地調用函數。args是一個包含將要提供給函數的按位置傳遞的參數的元組。若是省略了args,則任何參數都不會被傳遞,kwargs是一個包含關鍵字參數的字典。
Python3中已經再也不支持apply()函數,因此將
-apply(self.func,self.args)
修改成
Self.func(*self.args)
最後,線程的建立與啓動與前面的例子相同,惟一的區別是建立線程使用的是MyThreads類,線程的入參形式也有所改變。