今天突然觉得join函数好陌生 忘了是干嘛了的,所得花点回顾了一下。
了解线程的知识 请点 --->> 了解更多的线程知识
想要彻底了解join()就要先理解守护线程:
守护线程的工作方式类似服务器,只要没有客户端发来请求,就一直运行并且保持空闲,很像是后台。threading模块建立的线程除了守护线程之外,其余的线程都会在主线程结束之前结束掉。也就是说一般会先解决非守护线程的,所以相比而言,守护线程好像就“没那么重要”。设置守护线程使用,要在线程启动之前就设置好
接下来是join():
threading模块中join()的作用是为了防止子线程没结束主线程就先结束了,join()对于创建的普通的线程(除了守护线程)是没有多大作用的,有跟没有一样,都是要等到子线程结束后才会执行主线程。守护线程相比普通的线程显得“没有那么重要”,所以主线程一般不等它结束就先结束了。如果是作为守护线程使用join(),那么就会等待守护线程结束后才会执行主线程。
下面请看非守护线程使用join(),不使用join(),以及守护线程使用join()和不使用的具体实例
1.非守护线程不使用join()
from threading import Thread
import time
def dance(num):
for i in range(num):
print("正在跳舞", i)
time.sleep(2)
def sing(num):
for i in range(num):
print("正在唱歌", i)
time.sleep(2)
def main():
t1 = Thread(target=dance, args=(3,))
t2 = Thread(target=sing, args=(3,))
t1.start()
t2.start()
if __name__ == '__main__':
main()
print("程序结束了")
执行结果:
可以看到 : 子线程 还没有全部执行结束,主线程就先执行了,然后再回来执行 子线程 到结束。
2.守护线程不使用join()
from threading import Thread
import time
def dance(num):
for i in range(num):
print("正在跳舞", i)
time.sleep(2)
def sing(num):
for i in range(num):
print("正在唱歌", i)
time.sleep(2)
def main():
t1 = Thread(target=dance, args=(3,))
t2 = Thread(target=sing, args=(3,))
t1.setDaemon(True) # 设置t1为守护线程
t2.setDaemon(True) # 设置t2为守护线程
t1.start()
t2.start()
if __name__ == '__main__':
main()
print("程序结束了")
执行结果:
可以看到:守护的子线程还没有执行结束,主线程就先执行完了,并且主线程也不再回头 执行子线程了
(突然觉得守护线程的地位好低,有木有,被人抛弃了)
3.非守护线程使用join():
from threading import Thread
import time
def dance(num):
for i in range(num):
print("正在跳舞", i)
time.sleep(2)
def sing(num):
for i in range(num):
print("正在唱歌", i)
time.sleep(2)
def main():
t1 = Thread(target=dance, args=(3,))
t2 = Thread(target=sing, args=(3,))
t1.start()
t2.start()
t1.join()
if __name__ == '__main__':
main()
print("程序结束了")
执行结果:
可以看出:当给t1 t2 任意一个 子线程 加上join()之后,主线程 要等到 子线程 全部执行完,主线程才去执行。(地位超级高)
4.守护线程加上join():
from threading import Thread
import time
def dance(num):
for i in range(num):
print("正在跳舞", i)
time.sleep(2)
def sing(num):
for i in range(num):
print("正在唱歌", i)
time.sleep(2)
def main():
t1 = Thread(target=dance, args=(3,))
t2 = Thread(target=sing, args=(3,))
t1.setDaemon(True)
t2.setDaemon(True)
t1.start()
t2.start()
t1.join()
if __name__ == '__main__':
main()
print("程序结束了")
执行结果:
可以看出:给 守护线程 加上join()后, 主线程需要等到 守护线程 全部执行完毕后,主线程才执行。(守护线程的地位提高了好多)
那要是给join()加上参数呢? 例如:join(2)
加上参数2的意思是,主线程就给子线程2s的执行时间,2s一到,不管你子线程执行结束了没有,我主线程都要执行
5. join(2)的 非守护线程
from threading import Thread
import time
def dance(num):
for i in range(num):
print("正在跳舞", i)
time.sleep(2)
def sing(num):
for i in range(num):
print("正在唱歌", i)
time.sleep(2)
def main():
t1 = Thread(target=dance, args=(3,))
t2 = Thread(target=sing, args=(3,))
t1.start()
t2.start()
t1.join(2)
if __name__ == '__main__':
main()
print("程序结束了")
执行结果:
可以看出:2s时间一到,主线程就开始执行了,不过主线程执行完毕后,又回头来继续执行子线程到结束。
那么守护线程呢?
6.join(2)的守护线程:
from threading import Thread
import time
def dance(num):
for i in range(num):
print("正在跳舞", i)
time.sleep(2)
def sing(num):
for i in range(num):
print("正在唱歌", i)
time.sleep(2)
def main():
t1 = Thread(target=dance, args=(3,))
t2 = Thread(target=sing, args=(3,))
t1.setDaemon(True)
t2.setDaemon(True)
t1.start()
t2.start()
t1.join(2)
if __name__ == '__main__':
main()
print("程序结束了")
执行结果:
可以看出: 2s一到主线程开始执行,主线程执行结束后,也不再回去执行子线程了。(守护线程又被抛弃了)
7.join()位置带来不同结果:
我们给t1线程加上join(),放在了t2线程的前面:
from threading import Thread
import time
def dance(num):
for i in range(num):
print("正在跳舞", i)
time.sleep(2)
def sing(num):
for i in range(num):
print("正在唱歌", i)
time.sleep(2)
def main():
t1 = Thread(target=dance, args=(3,))
t2 = Thread(target=sing, args=(3,))
t1.start()
t1.join(2)
t2.start()
if __name__ == '__main__':
main()
print("程序结束了")
执行结果:
可以看出:t1全部执行完毕后,接下来主线程开始执行,最后是t2执行
个人总结:join()的作用其实就是给所添加的子线程一个优先执行的权利,等加上join()的子线程执行完毕之后,其他线程再执行。
而守护线程和普通线程区别就是:
守护线程会随着非守护线程结束而结束(比如主线程和其他副线程)。
守护线程:只要主线程执行完毕,不等其他线程,就退出程序
就是等待非守护线程执行完毕就退出。