join和 Daemon守护线程
一、前言
一个程序至少有一个主线程,主线程启动子线程后,它们之间并没有隶属关系。主线程和子线程执行是并行的,相互独立。主线程执行完毕后默认不等子线程执行结束就接着往下走了,如果有其他程序就会运行另外的程序,如果没有就等待子线程执行完成后结束程序。
结果:
二、join 等待子线程完成
如果在线程实例后加上join默认主线程是阻塞的,主线程会等待该子线程运行完成后在结束。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
|
# -*- coding: UTF-8 -*- import threading import time import random class MyThread(threading.Thread): def __init__( self , n): super (MyThread, self ).__init__() self .n = n def run( self ): print ( 'task %s is operating' % self .n) t_time = random.randint( 1 , 8 ) time.sleep(t_time) print ( self .getName(), 'finished' , 'I sleep %d seconds' % t_time) if __name__ = = '__main__' : start_time = time.time() for i in range ( 5 ): t = MyThread(i) t.start() t.join() # 添加join,阻塞主线程 print ( 'main thread finished.' ) print ( 'cost: %s' % (time.time() - start_time)) # 注 # 如果对每个线程都加join,那么并发就没有了,实际上线程都是串行的 # 前一个线程执行完了,才会执行下一个线程 # 主线程最后运行完毕 |
结果:
2.1 计算并发运行时间
如果不想计算出总的运行时间,而是所有线程的并发运行时间呢?就像上例中的那样,最长运行时间是8秒,那么所有线程都能在8秒内全部运行完毕。
把t.join()单独移到for循环外面是不行的,因为这样并发运行总会在最后一个线程出阻塞。如下:
结果:
正确的方法,定义一个空列表,获取所以的线程实例,for 循环阻塞所有的线程实例
结果,事实上也符合我们刚才的推论,运行时间最长的线程所消耗的时间,就是总的并发时间
总结:主线程创建一个子线程后,如果子线程调用join()方法,主线程会在调用的地方等待,直到该子线程运行完成才会接着往下执行。
三、守护线程setDaemon
setDaemon()方法:在主线程中创建子线程,该子线程调用setDaemon方法后成为主线程的守护线程。这种情况下如果主线程执行结束,那么不管子线程是否完成,一并和主线程退出。这里基本和join()方法相反。此外,还有个要特别注意的:必须在start() 方法调用之前设置,如果不设置为守护线程,程序会被无限挂起。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
# -*- coding: UTF-8 -*- import threading import time import random class MyThread(threading.Thread): def __init__( self , n): super (MyThread, self ).__init__() self .n = n def run( self ): print ( 'task %s is operating' % self .n) t_time = random.randint( 1 , 8 ) time.sleep(t_time) print ( self .getName(), 'finished' , 'I sleep %d seconds' % t_time) if __name__ = = '__main__' : start_time = time.time() for i in range ( 5 ): t = MyThread(i) t.setDaemon( True ) t.start() print ( 'main thread finished.' , threading.current_thread(), threading.active_count()) print ( 'cost: %s' % (time.time() - start_time)) |
注:threading.current_thread()查看当前运行的线程
threading.active_count() 查看活跃线程数
线程数 = 主线程 + 子线程数
结果:
1
2
3
4
5
6
7
8
9
10
11
|
task 0 is operating task 1 is operating task 2 is operating task 3 is operating task 4 is operating main thread finished. <_MainThread(MainThread, started 8656 )> 6 cost: 0.0009999275207519531 Process finished with exit code 0 # 很显然把子线程设置为主线程的守护线程后,主线程一旦结束,程序就执行退出运行,不会再等待子线程运行。 |
注:如果程序中有其他非守护线程时,还是会等待非守护线程运行完毕,程序才会结束。