threading模塊提供了管理多個線程執行的API。
最簡單的用法。就是用一個目標函數實例化一個Thread對象。start()開始工作,join()等待當前線程完成。
1: import threading2: def work():3: print("working")4: for i in range(5):5: t = threading.Thread(target=work)6: t.start()7: print("please wait!")8: t.join()
結果
1: working2: please wait!3: working4: please wait!5: working6: please wait!7: working8: please wait!9: working10: please wait!
當然也可以傳遞參數。
1: import threading2: def work(i):3: print("%i is working" %i)4: for i in range(5):5: t = threading.Thread(target=work,args=(i,))6: t.start()7: print("please wait!")8: t.join()
結果
1: 0 is working2: please wait!3: 1 is working4: please wait!5: 2 is working6: please wait!7: 3 is working8: please wait!9: 4 is working10: please wait!
確定當前線程
每個Thread實例都有一個帶有默認值的名字,也可以傳入name參數更改。
1: import threading2: import time3: def work():4: print(threading.current_thread().getName(),"starting!")5: time.sleep(0.5)6: print(threading.current_thread().getName(),"end!")7:8: t = threading.Thread(name="worker", target=work)9: t.start()10: print("please wait!")11: t.join()
結果
1: worker starting!2: please wait!3: worker end!
出於線程安全的考慮,我們下面用logging模塊輸出消息。
守護線程與非守護線程
一般來說,程序都會等待所有線程完成工作之后才退出。而守護線程可以一直運行而不阻塞主程序的退出。傳入daemon=True或者調用setDaemon()方法並提供參數True來構造守護線程。
1: import threading2: import time3: import logging4: def daemon():5: logging.debug("start")6: time.sleep(0.5)7: logging.debug("exite")8: def non_deamon():9: logging.debug("start")10: logging.debug("exit")11: logging.basicConfig(12: level=logging.DEBUG,13: format='(%(threadName)-10s) %(message)s',14: )15: d = threading.Thread(name='deamon', target=daemon, daemon=True)16: t = threading.Thread(name="non-deamon", target=non_deamon)17: d.start()18: t.start()
結果中沒有看到守護線程的退出的消息,主程序就已經退出了。
1: (deamon ) start2: (non-deamon) start3: (non-deamon) exit
要等待一個守護線程結束,需要使用join()方法。默認下,join會無限阻塞,但可以傳入浮點值。在時間內線程即使未完成,join也會強制返回。
1: import threading2: import time3: import logging4: def daemon():5: logging.debug("start")6: time.sleep(0.5)7: logging.debug("exite")8: def non_deamon():9: logging.debug("start")10: logging.debug("exit")11: logging.basicConfig(12: level=logging.DEBUG,13: format='(%(threadName)-10s) %(message)s',14: )15: d = threading.Thread(name='deamon', target=daemon, daemon=True)16: t = threading.Thread(name="non-deamon", target=non_deamon)17: d.start()18: d.join(0.2)19: t.start()
結果還是沒有看到守護線程的結束退出的消息。
1: (deamon ) start2: (non-deamon) start3: (non-deamon) exit
枚舉所有線程
threading.enumerate()會返回一個Thread實例的一個列表。由於等待當前主程序終止會引入一種死鎖的情況,所以跳過這個線程等待。注意根據電腦配置,合理調節線程睡眠時間,否則會由於缺少logging參數而報錯。
上述程序各個線程執行的順序1: import threading2: import time3: import logging4: import random5: def worker():6: pause = random.randint(1, 5) / 27: logging.debug("sleeping %0.2f" % pause)8: time.sleep(pause)9: logging.debug("end!")10: logging.basicConfig(11: level=logging.DEBUG,12: format='(%(threadName)-10s) %(message)s',13: )14: for i in range(3):15: t = threading.Thread(target=worker, daemon=True)16: t.start()17: # 拿到當前主線程18: main_thread = threading.main_thread()19: for t in threading.enumerate():20: if t is main_thread:21: continue22: logging.debug("joining %s" % t.getName())23: t.join()
輸出順序可能不一樣,
1: (Thread-1 ) sleeping 0.502: (Thread-2 ) sleeping 1.503: (Thread-3 ) sleeping 2.004: (MainThread) joining Thread-15: (Thread-1 ) end!6: (MainThread) joining Thread-27: (Thread-2 ) end!8: (MainThread) joining Thread-39: (Thread-3 ) end!
