threading模块提供了管理多个线程执行的API。
最简单的用法。就是用一个目标函数实例化一个Thread对象。start()开始工作,join()等待当前线程完成。
import threading
def work():
print("working")
for i in range(5):
t = threading.Thread(target=work)
t.start()
print("please wait!")
t.join()
结果
working
please wait!
working
please wait!
working
please wait!
working
please wait!
working
当然也可以传递参数。
import threading
def work(i):
print("%i is working" %i)
for i in range(5):
t = threading.Thread(target=work,args=(i,))
t.start()
print("please wait!")
t.join()
结果
0 is working
please wait!
1 is working
please wait!
2 is working
please wait!
3 is working
please wait!
4 is working
please wait!
确定当前线程
每个Thread实例都有一个带有默认值的名字,也可以传入name参数更改。
import threading
import time
def work():
print(threading.current_thread().getName(),"starting!")
time.sleep(0.5)
print(threading.current_thread().getName(),"end!")
t = threading.Thread(name="worker", target=work)
t.start()
print("please wait!")
t.join()
结果
worker starting!
please wait!
worker end!
出于线程安全的考虑,我们下面用logging模块输出消息。
守护线程与非守护线程
一般来说,程序都会等待所有线程完成工作之后才退出。而守护线程可以一直运行而不阻塞主程序的退出。传入daemon=True或者调用setDaemon()方法并提供参数True来构造守护线程。
import threading
import time
import logging
def daemon():
logging.debug("start")
time.sleep(0.5)
logging.debug("exite")
def non_deamon():
logging.debug("start")
logging.debug("exit")
logging.basicConfig(
level=logging.DEBUG,
format='(%(threadName)-10s) %(message)s',
)
d = threading.Thread(name='deamon', target=daemon, daemon=True)
t = threading.Thread(name="non-deamon", target=non_deamon)
d.start()
t.start()
结果中没有看到守护线程的退出的消息,主程序就已经退出了。
(deamon ) start
(non-deamon) start
(non-deamon) exit
要等待一个守护线程结束,需要使用join()方法。默认下,join会无限阻塞,但可以传入浮点值。在时间内线程即使未完成,join也会强制返回。
import threading
import time
import logging
def daemon():
logging.debug("start")
time.sleep(0.5)
logging.debug("exite")
def non_deamon():
logging.debug("start")
logging.debug("exit")
logging.basicConfig(
level=logging.DEBUG,
format='(%(threadName)-10s) %(message)s',
)
d = threading.Thread(name='deamon', target=daemon, daemon=True)
t = threading.Thread(name="non-deamon", target=non_deamon)
d.start()
d.join(0.2)
t.start()
结果还是没有看到守护线程的结束退出的消息。
deamon ) start
(non-deamon) start
(non-deamon) exit
枚举所有线程
threading.enumerate()会返回一个Thread实例的一个列表。由于等待当前主程序终止会引入一种死锁的情况,所以跳过这个线程等待。注意根据电脑配置,合理调节线程睡眠时间,否则会由于缺少logging参数而报错。
上述程序各个线程执行的顺序
输出顺序可能不一样,
(Thread-1 ) sleeping 2.50
(Thread-2 ) sleeping 2.00
(Thread-3 ) sleeping 0.50
(MainThread) joining Thread-1
(Thread-3 ) end!
(Thread-2 ) end!
(Thread-1 ) end!
(MainThread) joining Thread-2
(MainThread) joining Thread-3