python高性能編程--003--線程之Thread和threading
在Win32和Linux, Solaris, MacOS, BSD等大多數類Unix系統上運行時,Python支持多線程編程。Python使用POSIX兼容的線程,即pthreads。
默認情況下,源碼安裝的版本在2.0及以上的python;
win32的安裝包中;
線程默認是打開的。
bogon:~ elaine$ python Python 2.7.10 (default, Feb 7 2017, 00:08:15) [GCC 4.2.1 Compatible Apple LLVM 8.0.0 (clang-800.0.34)] on darwin Type "help", "copyright", "credits" or "license" for more information. >>> import thread >>>
直接在命令行下import thread,如果不報錯,則說明線程支持是打開的。
如果你的Python解釋器在編譯時,沒有打開線程支持,導入模塊會失敗,這種情況下,你就要重新編譯你的Python解釋器才能使用線程。
你可以在運行配置腳本的時候,加上“-with-thread”參數。
無線程支持的情況:
onethr.py
#!/usr/bin/python from time import sleep,ctime def loop0(): print ‘start loop 0 at:‘,ctime() sleep(4) print ‘loop 0 done at:‘,ctime() def loop1(): print ‘start loop 1 at:‘,ctime() sleep(2) print ‘loop 1 done at:‘,ctime() def main(): print ‘starting at:‘,ctime() loop0() loop1() print ‘all DONE at:‘,ctime() if __name__ == ‘__main__‘: main()
輸出結果:
/System/Library/Frameworks/Python.framework/Versions/2.7/bin/python2.7 /data/study/python/project/test/onethr.py starting at: Mon Mar 26 09:21:46 2018 start loop 0 at: Mon Mar 26 09:21:46 2018 loop 0 done at: Mon Mar 26 09:21:50 2018 start loop 1 at: Mon Mar 26 09:21:50 2018 loop 1 done at: Mon Mar 26 09:21:52 2018 all DONE at: Mon Mar 26 09:21:52 2018 Process finished with exit code 0
從上述輸出結果可看出,在沒有線程支持的情況下,即為在單線程中順序執行,上述代碼中有兩個循環,一個循環loop0結束後,另外一個循環loop1執行,整個程序的運行時間是兩個循環的運行時間的總和(6s)。
其實上述代碼中的兩個循環是可以同時運行的,這樣整個程序的運行時間為耗時最長的循環對應的運行時間。
如loop0運行時間為4s,loop1運行時間為2s,則整個程序運行時間為4s。
為了提高程序的運行效率,python中有了多線程編程。
python有幾個用於多線程編程的模塊:thread,threading和Queue等。
thread模塊提供了基本的線程和鎖支持;
threading模塊出了提供了基本的線程和鎖支持,還提供了更高級別,功能更強的線程管理功能;
Queue模塊是一個隊列數據結構,用於實現多個進程之間數據共享。
二、thread模塊
在實際項目中,不建議使用thread模塊,因該模塊有一個致命的缺陷:
當主線程結束時,所有的線程都會被強制結束,沒有任何的告警和正常的線程清除工作,這個是沒辦法接受的。
模塊函數:
start_new_thread()
產生一個新的線程,在新線程中用指定的參數和可選的kwargs來調用這個函數。allocate_lock()
分配一個LockType類型的鎖對象。exit()
讓線程退出。
LockType類型鎖對象方法:
acquire()
嘗試獲取鎖對象。locked()
如果獲取了鎖對象則返回True,否則返回False。release()
釋放鎖。
#!/usr/bin/python
from time import sleep,ctime
import thread
def loop0():
print ‘start loop 0 at:‘,ctime()
sleep(4)
print ‘loop 0 done at:‘,ctime()
def loop1():
print ‘start loop 1 at:‘,ctime()
sleep(2)
print ‘loop 1 done at:‘,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()
輸出結果:
/System/Library/Frameworks/Python.framework/Versions/2.7/bin/python2.7 /data/study/python/project/test/onethr.py
starting at: Mon Mar 26 13:10:30 2018
start loop 0 at: Mon Mar 26 13:10:30 2018
start loop 1 at: Mon Mar 26 13:10:30 2018
loop 1 done at: Mon Mar 26 13:10:32 2018
loop 0 done at: Mon Mar 26 13:10:34 2018
all DONE at: Mon Mar 26 13:10:36 2018
Process finished with exit code 0
start_new_thread(loop0,())是至少需要兩個參數,一個是函數,一個是傳遞給函數的值。
從上述輸出結果可以看出,loop0和loop1是同時運行的,即為並發執行。
在主線程中有一行代碼:sleep(6)
這行代碼的作用是讓主線程停止下來,因為如果沒有該行代碼,主進程在運行了兩個子線程後,主線程不會等待子線程執行完成就繼續往下執行,這就會導致子線程沒有執行完成,主線程直接打印輸出”all DONE“,啟動的兩個子進程就會被動退出結束,這是不可取的。
在這段代碼中,我們沒有讓主線程停下來等待所有子線程技術後再繼續運行剩下的代碼。
sleep(6)作用就是一種同步機制。
應該要有一種線程管理方法,而不是用sleep這種不靠譜的同步機制。
不讓主線程過早或過晚退出,引入了鎖的機制。
loops=[4,2]
def loop0(nloop,nsec,lock):
print ‘start loop ‘,nloop,‘at:‘,ctime()
sleep(nsec)
print ‘loop ‘,nloop,‘done at:‘,ctime()
lock.release()
def main():
print ‘starting at:‘,ctime()
locks = []
nloops = range(len(loops))
for i in nloops:
lock = thread.allocate_lock()
lock.acquire()
locks.append(lock)
for i in nloops:
thread.start_new_thread(loop0,(i,loops[i],locks[i]))
sleep(1)
for i in nloops:
while locks[i].locked():pass
print ‘all DONE at:‘,ctime()
if __name__ == ‘__main__‘:
main()
輸出結果:
/System/Library/Frameworks/Python.framework/Versions/2.7/bin/python2.7 /data/study/python/project/test/onethr.py
starting at: Mon Mar 26 13:32:09 2018
start loop 0 at: Mon Mar 26 13:32:09 2018
start loop 1 at: Mon Mar 26 13:32:10 2018
loop 1 done at: Mon Mar 26 13:32:12 2018
loop 0 done at: Mon Mar 26 13:32:13 2018
all DONE at: Mon Mar 26 13:32:13 2018
Process finished with exit code 0
三、threading模塊
python高性能編程--003--線程之Thread和threading