深圳 建設(shè)銀行國際互聯(lián)網(wǎng)站網(wǎng)絡(luò)推廣公司排名
_thread模塊除了可以派生線程外,還提供了基本的同步數(shù)據(jù)結(jié)構(gòu),又稱為鎖對象(lock object,也叫原語鎖、簡單鎖、互斥鎖、互斥和二進(jìn)制信號量)。
下面是常用的線程函數(shù):
函數(shù) | 描述 |
start_new_thread(function,args,kwargs=None) | 派生一個新的線程,使用給定的args和可選的kwargs來執(zhí)行function |
allocate_lock() | 分配LockType對象 |
exit() | 退出線程指令 |
LockType鎖對象的方法 | |
acquire(wait=None) | 嘗試獲取鎖對象 |
locked() | 如果獲取了鎖對象則返回True,否則返回False |
release() | 釋放鎖 |
_thread模塊的核心函數(shù)是start_new_thread()。專門用來派生新的線程。
我們對上節(jié)文章的onethr.py文件稍作修改:
#!/usr/bin/env pythonimport _thread
from time import sleep,ctimedef loop0():print('開始循環(huán)0次在:',ctime())sleep(4)print('結(jié)束循環(huán)0次在:',ctime())def loop1():print('開始循環(huán)1次在:',ctime())sleep(2)print('結(jié)束循環(huán)1次在:',ctime())'''
def main():print('開始于:',ctime())loop0()loop1()print('所有的任務(wù)都完成于:',ctime())
''' def main():print('starting at:', ctime())_thread.start_new_thread(loop0, ())_thread.start_new_thread(loop1, ())sleep(6)print('all done at:', ctime())if __name__ =='__main__':main(
執(zhí)行該腳本三遍,結(jié)果:
PS C:\Users\WC> python E:\Python3.6.3\workspace\mtsleepA.py
starting at: Mon Mar 26 21:56:10 2018
開始循環(huán)1次在: Mon Mar 26 21:56:10 2018
開始循環(huán)0次在: Mon Mar 26 21:56:10 2018
結(jié)束循環(huán)1次在: Mon Mar 26 21:56:12 2018
結(jié)束循環(huán)0次在: Mon Mar 26 21:56:14 2018
all done at: Mon Mar 26 21:56:16 2018
PS C:\Users\WC> python E:\Python3.6.3\workspace\mtsleepA.py
starting at: Mon Mar 26 22:00:43 2018
開始循環(huán)0次在: Mon Mar 26 22:00:43 2018
開始循環(huán)1次在: Mon Mar 26 22:00:43 2018
結(jié)束循環(huán)1次在: Mon Mar 26 22:00:45 2018
結(jié)束循環(huán)0次在: Mon Mar 26 22:00:47 2018
all done at: Mon Mar 26 22:00:49 2018
PS C:\Users\WC> python E:\Python3.6.3\workspace\mtsleepA.py
starting at: Mon Mar 26 22:00:56 2018
開始循環(huán)0次在: Mon Mar 26 22:00:56 2018
開始循環(huán)1次在: Mon Mar 26 22:00:56 2018
結(jié)束循環(huán)1次在: Mon Mar 26 22:00:58 2018
結(jié)束循環(huán)0次在: Mon Mar 26 22:01:00 2018
all done at: Mon Mar 26 22:01:02 2018
由上面的代碼可知,start_new_thread()必須包含兩個參數(shù),即使要執(zhí)行的函數(shù)不需要參數(shù),也要傳遞一個空元組。
我們注意到:loop0還是loop1開始的順序竟然可以是無序的;loop0和loop1是同時執(zhí)行的;loop1是在loop0之前結(jié)束的;整個程序一共耗時6秒。
我們可以說,loop0和loop1是并發(fā)執(zhí)行的。
我們在主程序(其實也就是主線程)中增加了一個sleep(6)的語句,這其實是為了避免主程序結(jié)束的時候,loop0和loop1兩個線程還沒有結(jié)束的問題。這也是_thread模塊的一種線程同步機制。
但是,我們要說這樣使用sleep()來進(jìn)行線程同步是不靠譜的,這也是_thread的一個弊端所在。
這時,我們可以引用鎖機制來實現(xiàn)相應(yīng)的線程管理,并且同時改善單獨的循環(huán)函數(shù)實現(xiàn)方式:
import _thread
from time import sleep, ctime
#不再把4秒和2秒硬性的編碼到不同的函數(shù)中,而是使用唯一的loop()函數(shù),并把這些常量放進(jìn)列表loops中
loops=[4,2]
#代替了之前的loop*()函數(shù),三個參數(shù)分別代表了處于第幾個循環(huán)中,睡眠時間和鎖對象。每個循環(huán)執(zhí)行到最后一句的時候,釋放鎖對象,告訴主線程該線程已完成
def loop(nloop,sec,lock):print('開始循環(huán)',nloop,'在:',ctime())sleep(sec)print('循環(huán)',nloop ,'結(jié)束于:',ctime())lock.release()def main():print('開始于:',ctime())locks=[]nloops=range(len(loops))#第一個for循環(huán)中,創(chuàng)建了一個鎖的列表,通過thread.allocate_lock()方法得到鎖對象,再通過acquire()方法取到鎖(相當(dāng)于把鎖鎖上),取到之后就可以把它添加到鎖列表locks中。for i in nloops:lock=_thread.allocate_lock()lock.acquire()locks.append(lock)#第二個for循環(huán)中,主要用于派生線程。每個線程都會調(diào)用loop()函數(shù),并傳遞循環(huán)號、睡眠時間以及用于該線程的鎖。 for i in nloops:_thread.start_new_thread(loop,(i,loops[i],locks[i]))#第三個for循環(huán),按照順序檢查每個鎖。每個線程執(zhí)行完畢后,都會釋放自己的鎖對象。這里使用忙等待,讓主線程等所有的鎖都釋放后才繼續(xù)執(zhí)行for i in nloops:while locks[i].locked():passprint('所有的任務(wù)完成于:',ctime())if __name__ =='__main__':main()
執(zhí)行結(jié)果:
開始循環(huán) 1 在: Mon Mar 26 22:49:25 2018 開始循環(huán) 0 在: Mon Mar 26 22:49:25 2018 循環(huán) 1 結(jié)束于: Mon Mar 26 22:49:27 2018 循環(huán) 0 結(jié)束于: Mon Mar 26 22:49:29 2018 所有的任務(wù)完成于: Mon Mar 26 22:49:29 2018
上述結(jié)果除了表名兩次循環(huán)是并發(fā)執(zhí)行的之外,整個程序一共用時4秒,而不是之前的6秒。