前言
进程靠线程执行代码,至少有一个主线程,其他线程是工作线程
主线程是第一个启动的线程
父线程:如果线程中启动了一个线程B,A就是B的父线程
子线程:B就是A的子线程
1. daemon属性
如果有non-daemon线程的时候,主线程退出时,也不会杀掉所有daemon线程,直到所有non-daemon线程全部结束,如果还有daemon线程,主线程需要退出,会结束所有daemon线程,退出
1.1 线程为 non-daemon
主线程扫描所有线程,只要存在non-daemon线程,主线程就等待non-daemon线程执行完毕后才退出
案例如下:
- 线程为non-daemon线程
import time
import threading
def foo():
time.sleep(5)
for i in range(5):
print(i)
#主线程是non-daemon线程,主进程
t = threading.Thread(target=foo,daemon=False)
t.start()
print('Main Thread Exiting')
#运行结果:
Main Thread Exiting
0
1
2
3
4
1.2 线程为 daemon
当主线程运行结束时,主线程不等待其他线程是否已经完成,直接退出程序
import time
import threading
def foo():
time.sleep(5)
for i in range(5):
print(i)
#主线程是non-daemon线程
t = threading.Thread(target=foo,daemon=True)
t.start()
#运行结果
Main Thread Exiting
1.3 两种线程共存
案列如下:
non-daemon线程执行时长大于daemon线程时
,表现为daemon线程也会执行完成
import time
import threading
def foo(n):
for i in range(n):
print(i)
time.sleep(1)
t1 = threading.Thread(target=foo,args=(2,),daemon=True)
t1.start()
t2 = threading.Thread(target=foo,args=(4,),daemon=False)
t2.start()
time.sleep(1)
print('Main Thread Exiting')
#运行结果
0
0
Main Thread Exiting
1
1
2
3
daemon线程执行时长大于non-daemon线程时
,表现为并非所有non-daemon线程会执行完成
import time
import threading
def foo(n):
for i in range(n):
print(i)
time.sleep(1)
t1 = threading.Thread(target=foo,args=(4,),daemon=True)
t1.start()
t2 = threading.Thread(target=foo,args=(2,),daemon=False)
t2.start()
time.sleep(1)
print('Main Thread Exiting')
#运行结果
0
0
Main Thread Exiting
1
1
说明主线程是否退出线程,取决于:进程内是否存储non-daemon线程,若不存在non-daemon时直接退出程序
2. join方法
join主要是阻塞功能,线程一旦join到某个父线程或者主线程时,父线程或主线程就阻塞到join位置,直到发起join的线程运行完成后才释放阻塞,通常在daemon线程中使用
import time
import threading
def foo(n):
for i in range(n):
print(i)
time.sleep(1)
t1 = threading.Thread(target=foo,args=(4,),daemon=True)
t1.start()
t1.join()
print('Main Thread Exiting')
#运行结果:
0
1
2
3
Main Thread Exiting
总结
join(timeout=None),是线程的标准方法之一
- 一个线程中调用另一个线程的join方法,调用者将被阻塞,直到被调用者线程终止。
- 一个线程可以被join多次
- timeout参数指定调用者等待多久,没有设置超时,就一直等待被调用线程结束
- 调用谁的join方法,就是join谁,就要等谁
3. 循环等待
3.1 event事件
event根据源码可知,event本身是一个类,在类属性中有一个flag属性,在flag的属性值初始为false,但是可以通过set方法重置为true,另外注意wait方法,wait在等待时间区间内,若flag从fasle重置为true,则wait函数返回值Ture,若没有发生变化,而且一旦set()后不再等待,则wait函数返回值为FALSE
,此项非常重要,可以利用此技巧进行循环等待。
3.2 event知识
在event类的学习过程中,要抛弃运维时学习到的模型,因为那些模型概念,仅仅是模型不能帮助你学习东西,返回会带来误解性的东西
名称 | 含义 |
---|---|
set() | 标记设置为True |
clear() | 标记设置为False |
is_set() | 标记是否为True |
wait(timeout=None) | 设置等待标记为True的时长,None为无限等待,等到返回True,未等到超时了返回False |
3.3 循环等待技巧
import threading from Event,Thread
def do(event:Event,interval:int):
while not event.wait(interval)
#循环等待,若event在等待interval周期内没有set(),返回false,因此再次进入循环
print('ok')
e = Event()
Thread(target=do,args=(e,3)).start()
e.wait(10)
e.set()
print("main exit")