Python教程

Python多线程之join()用法

本文主要是介绍Python多线程之join()用法,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

 

知识点:进程是分配资源的单位,线程是运算调度的单位。进程相当于资源,线程相当于控制流。

    当一个进程建立时,就会有一个主线程。

    进程当中的资源,如果只有一个线程在消耗,那无疑会余下空闲资源被浪费,此时就需要多线程去协同调度进程内的资源。

知识点:守护线程会随着主线程结束而结束,守护进程会随着主进程结束而结束。

    例如 QQ关闭时,聊天窗口一并关闭。QQ是进程,聊天窗口也是进程,不过是主进程与子进程(守护进程)的关系。

  setDaemon():设置守护线程

  threading.Thread(group=None, target=None, name=None, args=(), kwargs={}, *, daemon=None) 参数列表中target是指定执行的任务,args是传参

  Thread 的生命周期  

    1. 创建对象时,代表 Thread 内部被初始化。
    2. 调用 start() 方法后,thread 会开始运行。
    3. thread 代码正常运行结束或者是遇到异常,线程会终止。

  start()方法让线程进入runnable队列,具体什么时候执行,由cpu决定

  join()是阻塞,将当前子线程阻塞,主线程要等待一段时间后才能继续执行。

一、setDaemon(False) 即系统默认情况下的设置

程序代码:

import threading
import time


def run():
    """
    : 每个线程的任务都是run
    : thread.current_thread().name:当前线程名称
    :return: None
    """
    son_start_time = time.time()
    for i in range(1, 6):
        print(f"[线程 {threading.current_thread().name} 现在执行到了{i}]")
        time.sleep(1)
    print(f"[子线程{threading.current_thread().name}结束,耗时:{time.time() - son_start_time}]")


if __name__ == '__main__':
    start_time = time.time()
    # 用于装线程的列表
    thread_list = []
    # 依次新建 5 个 线程
    for i in range(5):
        thread_list.append(threading.Thread(target=run))
    # 多个线程依次设置 非 守护线程,并执行
    for i in thread_list:
        i.setDaemon(False)
        i.start()
    # 主线程等待三秒
    time.sleep(3)
    print(f"[主线程{threading.current_thread().name}结束啦 ! 耗时:{time.time() - start_time}] ")

结果如图:

 如上图所示,主线程在执行完自己的任务后便结束,子线程继续执行自己的任务。

当前是子线程无返回值的情况,主线程和子线程相关性并不大,那么子线程若是需要返回结果给主线程,其执行情况又是怎样呢?

实现过程如下:

"""
    title:多线程——join试验
    author:阿松不飞
"""

import threading
import time
from queue import Queue


def run(q):
    """
    : 每个线程的任务都是run
    : thread.current_thread().name:当前线程名称
    :return: res
    """
    son_start_time = time.time()
    for i in range(1, 6):
        print(f"[线程 {threading.current_thread().name} 现在执行到了{i}]")
        time.sleep(1)
    # q 调用put方法把将要返回的结果放入队列
    q.put(f"[子线程{threading.current_thread().name}结束,耗时:{time.time() - son_start_time}]")


if __name__ == '__main__':
    start_time = time.time()
    # 用于装线程的列表
    thread_list = []
    # 新建一个队列,用来装取结果
    q = Queue()
    # 依次新建 5 个 线程
    for i in range(5):
        # 将队列 q 传入线程方法当中
        thread_list.append(threading.Thread(target=run, args=(q,)))
    # 多个线程依次设置 非 守护线程,并执行
    for i in thread_list:
        i.setDaemon(False)
        i.start()
    # 依次取出 q 队列中的结果
    for i in range(5):
        print(q.get())
    # 主线程等待三秒
    time.sleep(3)
    print(f"[主线程{threading.current_thread().name}结束啦 ! 耗时:{time.time() - start_time}] ")

这个是队列存取结果的方案,因为我测试了 在run方法中放入return,然后主线程通过i.start() 获得返回值,结果总是None,便要换种获取结果的方案。

队列方案的运行结果如下:

那么由此可以看到,因为要获取到子线程的返回值,所以主线程的执行过程中,会有一个等待q队列的过程,而q队列会在等待子线程。

 

二、setDaemon(True)

  当setDaemon为true时,被设置的线程会成为主线程的守护线程。

  主线程若是结束,则会连带守护线程一起结束,守护线程不再执行,但是其余非守护线程还可以执行。

示例代码如下:

import threading
import time


def run():
    """
    : 每个线程的任务都是run
    : thread.current_thread().name:当前线程名称
    :return: res
    """
    son_start_time = time.time()
    for i in range(1, 6):
        print(f"[线程 {threading.current_thread().name} 现在执行到了{i}]")
        time.sleep(1)
    print(f"[子线程{threading.current_thread().name}结束,耗时:{time.time() - son_start_time}]")


if __name__ == '__main__':
    start_time = time.time()
    # 用于装线程的列表
    thread_list = []
    # 依次新建 5 个 线程
    for i in range(5):
        thread_list.append(threading.Thread(target=run))
    # 多个线程依次设置 非 守护线程,并执行
    for i in thread_list:
        i.setDaemon(True)
        i.start()
    # 主线程等待三秒
    time.sleep(3)
    print(f"[主线程{threading.current_thread().name}结束啦 ! 耗时:{time.time() - start_time}] ")

其结果如图:

  可以看到,当我设置了这些线程为守护线程之后, 主线程一旦执行完毕,守护线程随着主线程关闭

  那么接来下测试线程中join的作用

 运行代码:

import threading
import time


def run():
    """
    : 每个线程的任务都是run
    : thread.current_thread().name:当前线程名称
    :return: res
    """
    son_start_time = time.time()
    for i in range(1, 6):
        print(f"[线程 {threading.current_thread().name} 现在执行到了{i}]")
        time.sleep(1)
    print(f"[子线程{threading.current_thread().name}结束,耗时:{time.time() - son_start_time}]")


if __name__ == '__main__':
    start_time = time.time()
    # 用于装线程的列表
    thread_list = []
    # 依次新建 5 个 线程
    for i in range(5):
        thread_list.append(threading.Thread(target=run))
    # 多个线程依次设置 非 守护线程,并执行
    for i in thread_list:
        i.setDaemon(True)
        i.start()

    for i in thread_list:
        i.join()
    # 主线程等待三秒
    time.sleep(3)
    print(f"[主线程{threading.current_thread().name}结束啦 ! 耗时:{time.time() - start_time}] ")

其运行结果如下:

   

  当守护线程用上join方法的时候,join之中会有一个默认的timeout参数,在子线程执行过程中将阻塞主线程,让主线程去等待自己,等待的时长最大为timeout的时长,最短为子线程执行结束时间(<timeout时)。一旦等待超时,主线程不再等待,继续往下执行,当主线程执行结束,子线程也被关闭。

测试代码:

"""
    title:多线程——join试验
    author:阿松不飞
"""

import threading
import time


def run():
    """
    : 每个线程的任务都是run
    : thread.current_thread().name:当前线程名称
    :return: res
    """
    son_start_time = time.time()
    for i in range(1, 6):
        print(f"[线程 {threading.current_thread().name} 现在执行到了{i}]")
        time.sleep(1)
    print(f"[子线程{threading.current_thread().name}结束,耗时:{time.time() - son_start_time}]")


if __name__ == '__main__':
    start_time = time.time()
    # 用于装线程的列表
    thread_list = []
    # 依次新建 5 个 线程
    for i in range(5):
        thread_list.append(threading.Thread(target=run))
    # 多个线程依次设置 非 守护线程,并执行
    for i in thread_list:
        i.setDaemon(True)
        i.start()

    for i in thread_list:
        i.join(timeout=0.1)

    print(f"[主线程{threading.current_thread().name}结束啦 ! 耗时:{time.time() - start_time}] ")

 

执行结果:

 

 

 

这篇关于Python多线程之join()用法的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!