setDaemon和join区别

在科普什么是setDaemon和join之前,首先得明白进程与线程的概念。简而言之:代码在运行时,在内存中开辟了一个空间来运行这个代码块,在电脑的任务管理器可以进行查看,而这个代码在运行的时候,可能不止一个主线程在运行,也有可能出现多线程运行的情况。线程是一个顺序执行流,它是进程的组成部分,一个进程可以拥有多个线程。每个子线程和该父线程共享该进程的内存空间。

setDaemon和join区别_第1张图片

那么在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),而主线程(程序运行结束)的打印位置会发生变化。

以上为本人的理解,如有错误请留言纠正,谢谢。

 

 

你可能感兴趣的:(Python)