改变 Python 中线程执行顺序的方法


Posted in Python onSeptember 24, 2020

一、主线程会等待所有的子线程结束后才结束

首先我看下最普通情况下,主线程和子线程的情况。

import threading
from time import sleep, ctime

def sing():
 for i in range(3):
  print("正在唱歌...%d" % i)
  sleep(1)


def dance():
 for i in range(3):
  print("正在跳舞...%d" % i)
  sleep(1)


if __name__ == '__main__':
 print('---开始---:%s' % ctime())

 t1 = threading.Thread(target=sing)
 t2 = threading.Thread(target=dance)

 t1.start()
 t2.start()

 print('---结束---:%s' % ctime())

运行结果:

改变 Python 中线程执行顺序的方法

最后一行打印的代码就算在一开始运行了,程序也不会结束。

只有等待所有的子线程(sing 和 dance)都执行完毕,主线程才会结束,即程序结束。

二、默认状态下,多线程的执行顺序是不确定的

我们先来看一段代码:

import threading
import time

class MyThread(threading.Thread):
 def run(self):
  for i in range(3):
   time.sleep(1)
   msg = "I'm "+self.name+' @ '+str(i)
   print(msg)

def test():
 for i in range(5):
  t = MyThread()
  t.start()

if __name__ == '__main__':
 test()

运行结果:

I'm Thread-1 @ 0
I'm Thread-2 @ 0
I'm Thread-3 @ 0
I'm Thread-4 @ 0
I'm Thread-5 @ 0
I'm Thread-1 @ 1
I'm Thread-3 @ 1
I'm Thread-2 @ 1
I'm Thread-4 @ 1
I'm Thread-5 @ 1
I'm Thread-1 @ 2
I'm Thread-3 @ 2
I'm Thread-2 @ 2
I'm Thread-4 @ 2
I'm Thread-5 @ 2

每次的运行结果可能都不一样,但大体差不多。

说明:

从代码和执行结果我们可以看出,多线程程序的执行顺序是不确定的。

当执行到 sleep 语句时,线程将被阻塞,到 sleep 结束后,线程进入就绪状态,等待调度,而线程调度将自行选择一个线程执行。

上面的代码中只能保证每个线程都运行完整个 run 函数,但是线程的启动顺序、run 函数中每次循环的执行顺序都不能确定。

总结

每个线程默认有一个名字,尽管上面的例子中没有指定线程对象的 name,但是 python 会自动为线程指定一个名字。

当线程的 run() 方法结束时该线程完成。

无法控制线程调度程序,但可以通过别的方式来影响线程调度的方式。

三、Python daemon 守护线程详解

当程序中拥有多个线程时,主线程执行结束并不会影响子线程继续执行。

换句话说,只有程序中所有线程全部执行完毕后,程序才算真正结束。

Python 还支持创建另一种线程,称为守护线程(或后台线程)。

此类线程的特点是,当程序中主线程及所有非守护线程执行结束时,未执行完毕的守护线程也会随之消亡,程序将结束运行。

守护线程本质也是线程,因此其创建方式和普通线程一样,唯一不同之处在于,将普通线程设为守护线程,需通过线程对象调用其 damon 属性,将该属性的值改为 True。

注意:线程对象调用 daemon 属性必须在调用 start() 方法之前,否则 Python 解释器将报 RuntimeError 错误。

import threading

def action(len):
 for i in range(len):
  print(threading.current_thread().getName() + "," + str(i))

def main():
 t1 = threading.Thread(target=action, args=(10,))
 # 设置子线程为守护进程
 t1.daemon = True
 t1.start()

 for i in range(3):
  print(threading.current_thread().getName()+','+str(i))

if __name__ == "__main__":
 main()

运行结果:

Thread-1,0
MainThread,0
MainThread,1
MainThread,2

程序中,子线程里的程序就循环了一次,接着主线程执行完后,子线程就不打印信息了。

由于该程序中除了守护线程就只有主线程,因此只要主线程执行结束,则守护线程也随之消亡。

四、控制线程执行顺序

通过前面的学习我们知道,主线程和子线程会轮流获得 CPU 的资源。

但有时候,我们想让某个子线程先执行,然后再让主线程执行代码,该如何实现呢?

很简单,通过调用线程对象的 join() 方法即可。

join() 方法的功能是在程序指定位置,优先让该方法的调用者使用 CPU 资源。

该方法的语法格式如下:

thread.join( [timeout] )

timeout 参数作为可选参数,其功能是指定 thread 线程最多可以霸占 CPU 资源的时间(以秒为单位)。

如果省略,则默认直到 thread 执行结束(进入死亡状态)才释放 CPU 资源。

我们仍旧拿上面的例子来举例:

import threading

def action(len):
 for i in range(len):
  print(threading.current_thread().getName() + "," + str(i))

def main():
 t1 = threading.Thread(target=action, args=(10,))
 # 设置子线程为守护进程
 t1.daemon = True
 t1.start()
 t1.join()
 for i in range(3):
  print(threading.current_thread().getName()+','+str(i))

if __name__ == "__main__":
 main()

我们在子线程调用的后面,添加了 t1.join()。

运行结果:

Thread-1,0
Thread-1,1
Thread-1,2
Thread-1,3
Thread-1,4
Thread-1,5
Thread-1,6
Thread-1,7
Thread-1,8
Thread-1,9
MainThread,0
MainThread,1
MainThread,2

上面的例子中,t1 线程调用了 join() 方法,并且没有指定具体的 timeout 参数值。

这意味着如果程序想继续往下执行,必须先执行完 t1 子线程。

以上就是改变 Python 中线程的执行顺序的方法的详细内容,更多关于改变 Python 中线程的执行顺序的资料请关注三水点靠木其它相关文章!

Python 相关文章推荐
在Django中输出matplotlib生成的图片方法
May 24 Python
使用Python进行QQ批量登录的实例代码
Jun 11 Python
python单例模式获取IP代理的方法详解
Sep 13 Python
Python使用os.listdir()和os.walk()获取文件路径与文件下所有目录的方法
Apr 01 Python
pyQt5实时刷新界面的示例
Jun 25 Python
Python读取xlsx文件的实现方法
Jul 04 Python
Python selenium 加载并保存QQ群成员,去除其群主、管理员信息的示例代码
May 28 Python
python自定义函数def的应用详解
Jun 03 Python
Python包和模块的分发详细介绍
Jun 19 Python
Python使用OpenPyXL处理Excel表格
Jul 02 Python
如何使用Pytorch搭建模型
Oct 26 Python
python 爬取百度文库并下载(免费文章限定)
Dec 04 Python
浅析Python 字符编码与文件处理
Sep 24 #Python
学生如何注册Pycharm专业版以及pycharm的安装
Sep 24 #Python
python判断元素是否存在的实例方法
Sep 24 #Python
python 实现单例模式的5种方法
Sep 23 #Python
python zip()函数的使用示例
Sep 23 #Python
python 判断一组数据是否符合正态分布
Sep 23 #Python
python合并多个excel文件的示例
Sep 23 #Python
You might like
PHP获得用户使用的代理服务器ip即真实ip
2006/12/31 PHP
php zip文件解压类代码
2009/12/02 PHP
用PHP实现小写金额转换大写金额的代码(精确到分)
2012/01/10 PHP
PHP面向对象学习笔记之二 生成对象的设计模式
2012/10/06 PHP
PHP中遇到BOM、编码导致json_decode函数无法解析问题
2014/07/02 PHP
php使用wordwrap格式化文本段落的方法
2015/03/17 PHP
PHP memcache在微信公众平台的应用方法示例
2017/09/13 PHP
很酷的javascript loading效果代码
2008/06/18 Javascript
JSON JQUERY模板实现说明
2010/07/03 Javascript
jquery.tmpl JQuery模板插件
2011/10/10 Javascript
仿淘宝TAB切换搜索框搜索切换的相关内容
2014/09/21 Javascript
Express实现前端后端通信上传图片之存储数据库(mysql)傻瓜式教程(一)
2015/12/10 Javascript
jQuery插件HighCharts绘制2D带Label的折线图效果示例【附demo源码下载】
2017/03/08 Javascript
VUE饿了么树形控件添加增删改功能的示例代码
2017/10/17 Javascript
jquery的 filter()方法使用教程
2018/03/22 jQuery
Vue作用域插槽slot-scope实例代码
2018/09/05 Javascript
详解超简单的react服务器渲染(ssr)入坑指南
2019/02/28 Javascript
vue防止花括号{{}}闪烁v-text和v-html、v-cloak用法示例
2019/03/13 Javascript
jquery实现选项卡切换代码实例
2019/05/14 jQuery
vue子传父关于.sync与$emit的实现
2019/11/05 Javascript
JS面向对象编程实现的拖拽功能案例详解
2020/03/03 Javascript
[40:03]DOTA2上海特级锦标赛主赛事日 - 1 败者组第一轮#1EHOME VS Archon
2016/03/02 DOTA
[47:31]完美世界DOTA2联赛PWL S3 INK ICE vs DLG 第一场 12.12
2020/12/16 DOTA
Python 3中print函数的使用方法总结
2017/08/08 Python
python字典一键多值实例代码分享
2019/06/14 Python
使用tensorflow显示pb模型的所有网络结点方式
2020/01/23 Python
python自动下载图片的方法示例
2020/03/25 Python
Python中openpyxl实现vlookup函数的实例
2020/10/28 Python
详解canvas多边形(蜘蛛图)的画法示例
2018/01/29 HTML / CSS
ASICS印度官方网站:日本专业运动品牌
2020/06/20 全球购物
中专生职业生涯规划书范文
2013/12/29 职场文书
家长会欢迎标语
2014/06/24 职场文书
群众路线党员个人整改措施
2014/10/27 职场文书
出差报告格式模板
2014/11/06 职场文书
2014年医院党建工作总结
2014/12/20 职场文书
《绝招》教学反思
2016/02/20 职场文书