8-2-3python语法基础-并发编程-进程和线程对比学习:join和setDaemon,守护进程和守护线程
前言
进程和线程,有很多地方非常类似,包括使用的方法也很多相同的,
所以我决定放到一起对比学习,
这一篇,专门对比:
- 进程和守护进程,
- 线程和守护线程,
- join和setDaemon
进程和守护进程
daemon=True
import multiprocessing
import time
def f():
print("子进程1")
time.sleep(3)
print("子进程1运行结束")
if __name__ == '__main__':
# 定义一个子进程
use = multiprocessing.Process(target=f)
# 将子进程设置为守护进程
use.daemon = True
# 调用子进程
use.start()
print("程序运行结束")
输出结果:
程序运行结束
所以主进程结束,不管子进程有没有运行完,子进程也结束了,
daemon=False
import multiprocessing
import time
def f():
print("子进程1")
time.sleep(3)
print("子进程1运行结束")
if __name__ == '__main__':
# 定义一个子进程
use = multiprocessing.Process(target=f)
# 将子进程设置为守护进程
use.daemon = False
# 调用子进程
use.start()
print("程序运行结束")
输出结果:
程序运行结束
子进程1
子进程1运行结束
所以主进程虽然结束了,但是子进程还在运行,直到结束,也就是这个时候不管主进程有没有结束,子进程都会运行完才会结束
其实默认就是False,写不写这一句,运行结果都是一样的,
join()
import multiprocessing
import time
def f():
print("子进程1")
time.sleep(3)
print("子进程1运行结束")
if __name__ == '__main__':
# 定义一个子进程
use = multiprocessing.Process(target=f)
# 将子进程设置为守护进程
# 调用子进程
use.start()
use.join()
print("程序运行结束")
输出结果:
子进程1
子进程1运行结束
程序运行结束
所以主进程会等待所有的子进程都结束了,才会继续往下运行,
一般实际使用,都是daemon=True,并且加入join,这样既可以保证主进程最后运行,也可以保证主进程运行完了, 子进程都结束了,不会出现僵尸进程,
线程和守护线程
setDaemon方法
-
当一个进程启动之后,会默认产生一个主线程,因为线程是程序执行流的最小单元,当设置多线程时,主线程会创建多个子线程,
-
setDaemon这个方法,此方法是将子线程设置为守护线程。setDaemon放在start方法之前,可以理解为先设置完后再进行调用。
-
当主线程结束时根据子线程daemon(设置thread.setDaemon(True)),其中括号中可以填写True 或者False,属性值的不同,可能会发生下面的两种情况之一:
第一种情况:setDaemon(True)
- 如果某个子线程的daemon属性为True,
- 设置为true,意思就是把主线程A设置为守护线程,
- 这时候,要是主线程A执行结束了,就不管子线程B是否完成,一并和主线程A退出.
注意: - 1、守护线程会被其他最后一个线程或主线程终止。监听谁 就把谁设置守护线程
最常见的连用方式 thr.setDaemon(True), 后面thr.join() 注意不用加时间。或者加一个超时时间,超时时间一到主线程执行,执行结束后,进程自动关闭守护子线程。
import threading
import time
def f():
print("子线程1")
time.sleep(3)
print("子线程1运行结束")
if __name__ == '__main__':
# 定义一个子线程
use = threading.Thread(target=f)
# 将子线程设置为守护线程
use.setDaemon(True)
# 调用子线程
use.start()
print("程序运行结束")
输出结果:
子线程1
程序运行结束
所以不会执行子线程剩下的部分了,这就是主线程结束,子线程不管有没有完成,都结束,比较暴力,
第二种情况:setDaemon(False)
- 如果某个子线程的daemon属性为False,
- 主线程结束时会检测该子线程是否结束,如果该子线程还在运行,则主线程会等待它完成后再退出;
- 其实你如果不写setDaemon(False),默认就是这样的,所以如果是False,写不写这一句都一样,
注意:
- 1、主线程退出,子线程还可以在跑。线程之间都无关
import threading
import time
def f():
print("子线程1")
time.sleep(3)
print("子线程1运行结束")
if __name__ == '__main__':
# 定义一个子线程
use = threading.Thread(target=f)
# 将子线程设置为守护线程
use.setDaemon(False)
# 调用子线程
use.start()
print("程序运行结束")
输出结果:
子线程1
程序运行结束
子线程1运行结束
所以这种情况,就是主线程结束了,但是子线程还在执行一直到结束,
第三种情况:join的使用
import threading
import time
def f():
print("子线程1")
time.sleep(3)
print("子线程1运行结束")
if __name__ == '__main__':
# 定义一个子线程
use = threading.Thread(target=f)
# 将子线程设置为守护线程
# 调用子线程
use.start()
use.join()
print("程序运行结束")
输出结果:
子线程1
子线程1运行结束
程序运行结束
- 所以你发现了,主线程会等待子线程结束了才会继续执行,
join和setDaemon(True)setDaemon(False)对比
场景 | setDaemon(True) | setDaemon(False) | join |
---|---|---|---|
主线程结束了子线程是否继续运行? | × | √ | √ |
主线程等待子线程全部结束才运行 | × | × | √ |
进程和线程的使用区别
就是进程是使用属性赋值的方式,实现守护进程,
线程是使用方法的方法,实现的守护进程,
所以你明白为什么要对比学习了吧,
这种对比学习,可以让你印象更加的深刻,