4 - 线程 - Windows 10 - CPython - 理解伪多线程中 join() 线程连接点(主线程堵塞) 和 sleep() 线程睡眠 的作用

发布时间 2023-03-24 16:51:45作者: Loki_Severus

@


测试环境:

操作系统: Window 10
工具:Pycharm
Python: 3.7

一、join() 连接点的服务对象是子线程

join
n. 连接处,接合点

|
|主线程
|___  join() 连接点
|   |子线程
|   |
|	|
|
|   

主线程创建子线程对象,而子线程对象使用了 join()线程连接点方法后,当前的主线程就会从join()连接点开始堵塞,切换到某一个子线程运行,等到子线程完成它的程序后,会切换回主线程堵塞的位置,继续从主线程堵塞的位置执行下去。

sleep()time模块的一个函数,join()是线程模块 threading 的函数
sleep()堵塞的是当前的线程,而join()堵塞的是主线程 main,也就是说用了 join() 函数,那么主线程就必须等到该线程执行程序结束为止,才能运行主线程后面的程序。
比如

import threading
t1 = threading.Thread(target=test)
t1.join()

这代表着主线程就必须等待 t1 线程程序,执行结束为止,即便 t1 线程内存在了 sleep() 函数,堵塞该 t1 线程程序,也必须等到 sleep() 时间过后,再执行 t1 程序后面的代码,然后还得等到 t1 线程程序结束后,才会运行主线程的开启多线程代码后的其他代码。

二、sleep() - 线程睡眠的服务对象是主线程和子线程

特别注意time模块的sleep() 函数

sleep()的特别在于,它不在乎是在主线程或子线程中执行,它只在乎堵塞当前的线程,还有一点是线程睡眠 sleep() 在堵塞当前线程后,会切换线程执行,也就是说,在sleep() 后,那么该线程无法继续执行下去了,只能切换线程,让另外的线程去执行,除非线程睡眠设置的时间到了,才能有机会继续执行该线程,为什么说是有机会,因为线程的执行是随机的,你无法知道下一个被切换到执行的线程是哪一个。

如果通过sleep()将一个运行中的线程设置为线程睡眠后,那么在该线程睡眠期间,它是不会获得执行的机会的

题外话: 子线程是依托于主线程存在的,一个进程起码有一个线程,该线程指的是主线程,而主线程有可以使用此进程的资源去创建子线程,也就是多线程间的共享资源,线程可以说是轻量级的进程,进程之间可以互相通信。

进程与线程的并行与并发 —— 在同一时刻内,在计算机是多核的情况下是进程与进程间,线程与线程间是并行,在单核的情况下,进程与进程,线程与线程那就绝对是并发。
同一时刻内,4核的计算机,线程并行最多4个,除非使用了超线程,可以达到4核8线程。

场景 1:主线程 time 小于 子线程 time

(主线程要快过子线程)

sleep() 线程睡眠方法:

因为在主线程内使用了sleep() 线程睡眠函数,那么就会堵塞主线程,当sleep()设置的等待时间参数后,该等待时间的值小于子线程的执行时间时,即在主线程使用了线程睡眠sleep()方法,还是无法让主线程的运行时间比子线程的运行时间慢,相当于主线程程序执行的速度要快过子线程程序执行的速度 ,比如 主线程sleep(1)且实际运行结束需要 1 秒,那么主线程实际的运行时间的 1 秒 加上 sleep(1)线程睡眠方法的1 秒,总共需要花费 2 秒时间,而子线程需要花费 3 秒才可以执行完毕,那么当主线程 sleep(1),即线程睡眠 1秒后,继续运行主线程,运行1秒后,退出程序,而子线程还没有执行完毕,还差1秒钟,那么子线程就会被强制退出

join() 线程连接点方法:

使用了 join() 方法,就不用担心主线程会快过子线程,因为 join() 方法会强制让主线程等待子线程执行完毕,之后主线程才会继续下面程序执行。
如果是使用了 sleep() 方法,就需要指定停止线程运行的时间具体多长(s, 秒),而使用 join() 方法不需要设置停止时长,子线程运行多久,主线程也得跟着停止多久,即使比子线程执行的更快,也得等子线程完成了,才能退出执行。

场景 2:主线程 time 大于 子线程 time

(主线程要慢过子线程)

主线程sleep()线程睡眠设置的时间,大于子线程的执行时间,相当于主线程程序执行的速度要慢过子线程程序执行的速度 ,这里是主线程的程序实际运行时间加上线程睡眠时间,当子线程执行结束后,主线程都没执行完成。

————————————————————————————————————————

三、个人对 join 方法的深入理解:

在笔者看来,堵塞了主线程,那是否意味着子线程的执行函数被插入到了主线程堵塞的代码块那里,从而只能执行子线程的执行函数,等其执行函数执行完毕返回,然后才会开始继续执行主线程的接下来的代码。
因为线程是共享数据的原因,所以笔者才突发奇想,想到会不会这这样子的代码插入操作,而不会是多进程那样的工作队列排序堵塞操作。

————————————————————————————————————————

参考链接

进程与线程 - CPython 解释器 - 多线程并行(实际并发)

python中threading的join和setDaemon的区别和用法

终于想明白操作系统的中断和进程阻塞了