python中,有兩個標(biāo)準(zhǔn)模塊thread和threading可以實現(xiàn)多線程,不過threading更加高級,推薦使用threading。
threading 模塊提供的常用方法:
threading.currentThread(): 返回當(dāng)前的線程變量。
threading.enumerate(): 返回一個包含正在運行的線程的list。正在運行指線程啟動后、結(jié)束前,不包括啟動前和終止后的線程。
threading.activeCount(): 返回正在運行的線程數(shù)量,與len(threading.enumerate())有相同的結(jié)果。
threading.setName 設(shè)置線程名
threading.getName 獲得線程名
threading.Timer() 定時器,,每隔一段時間就開一一個線程調(diào)用一個函數(shù)
threading.Thread(target=方法名, name='線程名', args=參數(shù))啟動一個線程,返回一個進程對象 。
這里以主線程A,子線程B為例:
start() 調(diào)用B.start()開始執(zhí)行子線程
join() 調(diào)用B。join開始執(zhí)行,同時主線程會在調(diào)用的地方等待
setDaemon() 主線程A中調(diào)用了B.setDaemon(),這個的意思是,把主線程A設(shè)置為守護線程, 要是主線程A執(zhí)行結(jié)束了,就不管子線程B是否完成,一并和主線程A退出(和join相反)。必須在start() 方法調(diào)用之前設(shè)置
threading 模塊提供的常量:
threading.TIMEOUT_MAX 設(shè)置threading全局超時時間。
線程鎖
多線程中,除了線程自己的臨時變量, 所有全局或靜態(tài)變量都由所有線程共享,所以,任何一個變量都可以被任何一個線程修改。
因此,需要引入線程鎖給變量上一把鎖,當(dāng)某個線程開始執(zhí)行時,我們說,該線程因為獲得了鎖,因此其他線程不能同時執(zhí)行,只能等待。
balance = 0
lock = threading.Lock()
def run_thread(n):
for i in range(100000):
# 先要獲取鎖:
lock.acquire()
try:
# 放心地改吧:
change_it(n)
finally:
# 改完了一定要釋放鎖:
lock.release()
lock.acquire()時,只有一個線程能成功地獲取鎖,然后繼續(xù)執(zhí)行代碼,其他線程就繼續(xù)等待直到獲得鎖為止才能執(zhí)行l(wèi)ock.acquire()后的代碼。
獲得鎖的線程用完后一定要釋放鎖,否則那些苦苦等待鎖的線程將永遠等待下去,成為死線程。
python中, 線程對多核cpu無效
因為Python的線程雖然是真正的線程,但解釋器執(zhí)行代碼時,有一個GIL鎖:Global Interpreter Lock,任何Python線程執(zhí)行前,必須先獲得GIL鎖,然后,每執(zhí)行100條字節(jié)碼,解釋器就自動釋放GIL鎖,讓別的線程有機會執(zhí)行。這個GIL全局鎖實際上把所有線程的執(zhí)行代碼都給上了鎖,所以,多線程在Python中只能交替執(zhí)行,即使100個線程跑在100核CPU上,也只能用到1個核。
所以,在Python中,可以使用多線程,但不要指望能有效利用多核。