在科普什么是setDaemon和join之前,首先得明白进程与线程的概念。简而言之:代码在运行时,在内存中开辟了一个空间来运行这个代码块,在电脑的任务管理器可以进行查看,而这个代码在运行的时候,可能不止一个主线程在运行,也有可能出现多线程运行的情况。线程是一个顺序执行流,它是进程的组成部分,一个进程可以拥有多个线程。每个子线程和该父线程共享该进程的内存空间。
那么在python中如何调用多线程呢?python给我们提供了threading和_thread两个库,threading对_thread提供了封装。在threading模块中提供了Thread、Lock、RLock、Condition等组件。那么我们要提到的setDaemon和join两个方法。
首先了解以下join方法:阻塞线程,主线程进行等待。各位看官自己翻译,能力有限。
"""Wait until the thread terminates.
This blocks the calling thread until the thread whose join() method is
called terminates -- either normally or through an unhandled exception
or until the optional timeout occurs.
When the timeout argument is present and not None, it should be a
floating point number specifying a timeout for the operation in seconds
(or fractions thereof). As join() always returns None, you must call
isAlive() after join() to decide whether a timeout happened -- if the
thread is still alive, the join() call timed out.
When the timeout argument is not present or None, the operation will
block until the thread terminates.
A thread can be join()ed many times.
join() raises a RuntimeError if an attempt is made to join the current
thread as that would cause a deadlock. It is also an error to join() a
thread before it has been started and attempts to do so raises the same
exception.
"""
使用方法如下:定义了一个def,里面print两句话,并且使用sleep使两句话中间间隔时间为3秒,main函数调用该def,并定义其为一个子线程,最后在主线程前调用该子线程。
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("程序运行结束")
其输出结果为:(第一句和第二句中间间隔了3秒后,由于使用join方法,阻塞调用,使主线程等待子线程执行完毕后。顺序执行主线程,打印第三句后进程执行完毕)
子线程1
子线程1运行结束
程序运行结束
我们现在来讨论setDaemon这个方法,此方法是将子线程设置为守护线程。setDaemon放在start方法之前,可以理解为先设置完后再进行调用。其中括号中可以填写True 或者False,先讲解True。
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("程序运行结束")
运行结果:(既然设置了守护线程,主线程就不会像join方法一样等你子线程执行完毕后,在开始执行,它直接先行执行,然后你子线程才被开始调用。其中子线程的调用还是:先打印第一句话后,睡3秒,执行打印第二句话)
程序运行结束
子线程1
子线程1运行结束
在setDaemon参数中设置为False。其结果为:
子线程1
程序运行结束
子线程1运行结束
由于setDaemon(False)为单线程,代码从main进入,从上而下顺序执行,到了start方法,调用函数,调用子线程打印第一句话,后主线程抢回线程,原因是子线程睡了3秒,主线程执行完毕后,最后在返回子线程执行最后的打印。
假如子线程不睡,其结果又是怎么样的呢?
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运行结束
"""
子线程没有睡,则结果如下:(为了观察加了一个range观察调用情况)
import threading
import time
def f():
print("子线程1")
# time.sleep(3)
print("子线程1运行结束")
for i in range(5):
print(i)
if __name__ == '__main__':
# 定义一个子线程
use = threading.Thread(target=f)
# 将子线程设置为守护线程
use.setDaemon(False)
# 调用子线程
use.start()
print("程序运行结束")
'''
子线程1
子线程1运行结束
0
1
2
程序运行结束
3
4
'''
结果显示:子线程没有睡后,主线程会与子线程竞争线程的使用权,其运行结果不定。但是调用子线程的第一句话还是第一句(子线程1),而主线程(程序运行结束)的打印位置会发生变化。
以上为本人的理解,如有错误请留言纠正,谢谢。