threading模块提供了管理多个线程执行的API。
最简单的用法。就是用一个目标函数实例化一个Thread对象。start()开始工作,join()等待当前线程完成。
1: import threading
2: 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: working
2: please wait!
3: working
4: please wait!
5: working
6: please wait!
7: working
8: please wait!
9: working
10: please wait!
当然也可以传递参数。
1: import threading
2: 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 working
2: please wait!
3: 1 is working
4: please wait!
5: 2 is working
6: please wait!
7: 3 is working
8: please wait!
9: 4 is working
10: please wait!
确定当前线程
每个Thread实例都有一个带有默认值的名字,也可以传入name参数更改。
1: import threading
2: import time
3: 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 threading
2: import time
3: import logging
4: 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 ) start
2: (non-deamon) start
3: (non-deamon) exit
要等待一个守护线程结束,需要使用join()方法。默认下,join会无限阻塞,但可以传入浮点值。在时间内线程即使未完成,join也会强制返回。
1: import threading
2: import time
3: import logging
4: 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 ) start
2: (non-deamon) start
3: (non-deamon) exit
枚举所有线程
threading.enumerate()会返回一个Thread实例的一个列表。由于等待当前主程序终止会引入一种死锁的情况,所以跳过这个线程等待。注意根据电脑配置,合理调节线程睡眠时间,否则会由于缺少logging参数而报错。
1: import threading
2: import time
3: import logging
4: import random
5: def worker():
6: pause = random.randint(1, 5) / 2
7: 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: continue
22: logging.debug("joining %s" % t.getName())
23: t.join()
上述程序各个线程执行的顺序
![image image](https://i-blog.csdnimg.cn/blog_migrate/18f830e428abead7b2428e33f4af79c4.png)
输出顺序可能不一样,
1: (Thread-1 ) sleeping 0.50
2: (Thread-2 ) sleeping 1.50
3: (Thread-3 ) sleeping 2.00
4: (MainThread) joining Thread-1
5: (Thread-1 ) end!
6: (MainThread) joining Thread-2
7: (Thread-2 ) end!
8: (MainThread) joining Thread-3
9: (Thread-3 ) end!