守护多线程示例:
守护进程和守护线程
通常,默认的情况下,没有特殊的设置情况,通过主线程创建出来的子线程默认一般都是非守护线程或普通线程。默认情况下创建出来的线程,如果处于运行状态种的话(循环执行任务中),主线程会一直等待所有的子线程执行完成后才正常的退出。
非守护线程的示例:
import threading, time
def my_run(msg):
while True:
print("子线程的名称:", threading.current_thread().getName())
print("开始任务", msg)
time.sleep(2)
print("任务结束,", msg)
if __name__ == '__main__':
start_time = time.time()
t1 = threading.Thread(name='线程1', target=my_run, args=("我是你大爷!",))
t1.start()
time.sleep(2)
print('运行总耗时:', time.time() - start_time)
主要看:
t1 = threading.Thread(name='线程1', target=my_run, args=("我是你大爷!",))
这里没设置这个子线程是守护线程的情况下
我们的结果就算主线程执行到最后了,但是子线程没退出的情况下,还是会一直等待子线程执行结束:
子线程的名称: 线程1
开始任务 我是你大爷!
任务结束, 我是你大爷!
子线程的名称: 线程1
开始任务 我是你大爷!
运行总耗时:2.005869150161743
任务结束, 我是你大爷!
子线程的名称: 线程1
开始任务 我是你大爷!
·······
如果 是设置了守护线程的情况下:
t1 = threading.Thread(name='线程1',daemon=True, target=my_run, args=("我是你大爷!",))
新增了一个参数:daemon=True, 输出的结果则是:(结果运行多几次会不一样)
子线程的名称: 线程1
开始任务 我是你大爷!
任务结束, 我是你大爷!
子线程的名称: 线程1
开始任务 我是你大爷!
运行总耗时:2.011021375656128
一种情况:
子线程的名称: 线程1
开始任务 我是你大爷!
运行总耗时:2.0100226402282715
设置了守护线程之后,可能守护线程会在主线程代码执行结束后就终止····没有执行任务结束了~~~~~~~所以任何所有的守护程序线程如果在主线程执行完成之后,没执行完成的都会将在Python退出时被丢弃。
PS:主进程运行完毕指的是主线程所在的进程内所有非守护线程统统运行完毕,只要如果存在一个非守护线程没执行完毕,不管里面是有守护和非守护的,统统是需要等待非守护进程的执行,才完全退出python解释器。
守护线程是否能继续开子线程:
import threading, time
def zizixiancheng(msg):
print(msg)
def my_run(msg):
print("子线程的名称:", threading.current_thread().getName())
print("开始任务", msg)
time.sleep(2)
print("任务结束,", msg)
t1 = threading.Thread(name='子子线程---',target=zizixiancheng, args=("我是子子的线程~你大爷!",))
t1.start()
if __name__ == '__main__':
start_time = time.time()
t1 = threading.Thread(name='线程1',daemon=True,target=my_run, args=("我是你大爷!",))
t1.start()
time.sleep(5)
print('运行总耗时:', time.time() - start_time)
输出结果:
子线程的名称: 线程1
开始任务 我是你大爷!
任务结束, 我是你大爷!
我是子子的线程~你大爷!
运行总耗时:5.0077033042907715
所以,印证了守护线程是可以在开子线程的,和进程不一样(守护进程是不能再开子进程的)
回顾进程的守护概念:
守护进程的概念:
进程分为: 前台运行的进程 后台运行的进程, 其中守护进程属于后台运行的进程,是运行在后台中一种非常特殊进程。 它可以独立于控制终端并且周期性 地执行某种任务或等待处理某些发生的事件。
特点:
守护进程会在主进程代码执行结束后就终止。 守护进程内无法再开启子进程(不能怀孕),否则会抛出异常。
守护进程的效果:把相应的子进程设置为守护进程,主进程运行完毕之后,相关的守护进程也会随后结束,被回收!
守护进程设置的方法:
设置的方法:在p.start之前将p.daemon = True,默认情况下daemon为False.
#!/usr/bin/evn python
# -*- coding: utf-8 -*-
"""
-------------------------------------------------
文件名称 : test3
文件功能描述 : 功能描述
创建人 : 小钟同学
创建时间 : 2021/4/30
-------------------------------------------------
修改描述-2021/4/30:
-------------------------------------------------
"""
import os
print("程序开始执行--------》")
# print("外层的:os.getppid()",os.getpid())
# print("外层的:os.getppid()",os.getppid())
from multiprocessing import Process
import time
def func(name):
print('你好', name)
print("子进程内层的自己的进程ID:os.getpid()", os.getpid())
print("子进程内层的父进程ID:os.getppid()", os.getppid())
# 守护进程内无法再开启子进程,否则抛出异常
print("子进程内部可以在创建子进程(不能怀孕!)")
# p = Process(target=time.sleep, args=(3,))
# p.start()
if __name__ == "__main__":
p = Process(target=func,args=('沙和尚',))
# 设置的方法:在p.start之前将p.daemon = True,默认情况下daemon属性的数值为False.
p.daemon=True
p.start()
print("等待进程执行完毕!")
p.join() # 等待进程执行完毕
print("执行完成!")
注意事项:因为设置我们的子进程为守护进程, p.daemon=True所以它里面不可以在创建新的子进程。
在上面中,我们了解到其实>multiprocess库的出现很大程度上是为了弥补thread库因为GIL而低效的缺陷。
它完整的复制了一套thread所提供的接口方便迁移。 每个进程有自己的独立的GIL,因此也不会出现进程之间的GIL争抢,通过多进程的方式绕过GIL。
意思就是其实多数的进程和线程相关的接口设计上其实和进程大体是保持一致!
所以,通常我们的线程也会有主线程和子线程之分,也会有对应的所谓的守护子线程,所以守护线程和和守护进程一样,也会遵循上面的的几个特点:
特点:
守护进程(守护线程)会在主进程(主线程)代码执行结束后就终止。 守护进程(守护线程)内无法再开启子进程(子线程),否则会抛出异常。
当然需要强调的一点是:运行完毕并非终止运行
对主进程/主线程来说,运行完毕指的是主线程所在的进程内所有非守护线程统统运行完毕,主线程才算运行完毕
个人其他博客地址
简书:https://www.jianshu.com/u/d6960089b087
掘金:https://juejin.cn/user/2963939079225608
小钟同学 | 文 【原创】| QQ:308711822
1:本文相关描述主要是个人的认知和见解,如有不当之处,还望各位大佬指正。 2:关于文章内容,有部分内容参考自互联网整理,如有链接会声明标注;如没有及时标注备注的链接的,如有侵权请联系,我会立即删除处理哟。




