15. Python 程序运行速度如何提高十倍?第一遍滚雪球学 Python 收工
本篇文章将给大家介绍 Python 多线程与多进程相关知识,学习完该知识点之后,你的 Python 程序将进入另一个高峰。
<center><font color=red>缓解一下视疲劳</font></center>
<center><font color=red>缓解一下视疲劳</font></center>
已完成的文章
1.这才是 Python 学习的正确起手姿势,滚雪球学 Python
2. 无门槛学会数据类型与输入、输出函数,滚雪球学 Python
3. 无转折不编程,滚雪球学 Python
4. 列表一学完,Python 会一半,滚雪球学 Python
5. Python 循环的本质就是一段代码懒得重复写
6. Python 元组,不可变的列表,滚雪球学 Python
7. ✎ 会查新华字典不?会。Python 字典已经掌握了
8. ㊙ Python 集合三板斧,滚雪球学 Python
9. Python 学习过程的第一个山坡,99%的人都倒在了山坡下
10. 比找女朋友还难的技术点,Python 面向对象
11. 用别人写好的代码,完成我的工作,剩下的时间去摸鱼
12. 数据放在本地,心里才更踏实,滚雪球学 Python
13. 如果自己写的 Python 程序出错了,怎么办?
14. Python 与数据库那点事儿,滚雪球学 Python
**
本系列文章将在 2021 年春节前完成,欢迎关注,点赞,评论 --- 梦想橡皮擦
**
**想学 Python 爬虫,可以订阅橡皮擦专栏哦~
** 🈲🈲🈲 点击发现惊喜 🈲🈲🈲
十五、Python 多线程与多进程
先尝试理解线程与进程的概念,进程范围大,一个进程可能会包含多个线程,OK,了解到这一步就可以了,知道谁包含谁已经很不错了,细节的地方慢慢研究。
打开你电脑上的任务管理器,注意这里面以前说的叫做杀掉进程。
15.1 Python 多线程
让我们把视角转换一下,先从进程中抽离出来,看一下线程,在学习这部分内容的时候,这两个概念一定不要弄错,弄错就翻车了。
15.1.1 简单的多线程
如果一个线程只完成一个事情,那程序会变得特别呆板,例如现在你正在给编写一段代码,那你在编写代码的过程中,你使用的 IDE(代码编辑器)就完全不能做其它事情了,必须等到编写完所有代码之后才可以执行其它操作,所有的事情只能一件挨着一件的做。而且在这个线程会将资源霸占住,例如让其操作一个文件,必须等到它完成操作其它程序才可以使用,这叫做单线程。
如何实现多线程呢,通过导入 Python 内置的 threading
模块可以解决该问题。
建立一个线程使用的是 threading
模块中的 Thread
方法,该方法会创建一个 Thread 对象(线程对象),使用该方法的时候需要注意方法的参数值是一个函数名称,该参数为 target
,后面是线程要调用的函数名称,没有小括号。返回的线程对象在上述代码中叫做 my_thread
,自己定义的任意名称都是可以的,遵循变量命名规则即可。
线程的启动需要调用线程对象的 start
方法。
代码运行之后重点注意输出的顺序。
主线程结束
输出之后,需要等待几秒钟的时间,我们定义的子线程才会开始运行,即输出 时间到了,线程继续工作
。
15.1.2 子线程传递参数
在创建线程的时候,除了直接调用某函数,也可以向子线程中的函数里传递参数,具体语法格式如下:
具体案例如下,像 thread_work
函数中传递一个 橡皮擦
。
参数在传递的时候,需要与函数定义时参数匹配。多线程中不建议使用相同的变量,很容易出现问题,建议每个线程使用自己的局部变量,互相之间不要产生干扰。
15.1.3 线程命名
每个线程在启动之后,如果没有手动命名,系统会自动给其命名为 Thread-n
,在程序中可以使用 currentThread().getName()
获取线程的名称。随着 Python 版本的迭代,currentThread
方法已经逐步被 current_thread
替代。
代码运行结果如下,可以重点看一下线程默认的名称。
如果想要给线程起一个独特的名字,可以在通过 Thread 方法建立线程时,使用参数 name = "线程名称"
,该名称就是为线程单独命名。
除了上述办法以外,还可以使用 currentThread().setName()
给函数命名,自己可以尝试下哦~
15.1.4 Daemon 守护线程
默认创建的线程都不是 Daemon 线程,正常情况下,一个程序建立了主线程和子线程,那程序结束需要等待所有的线程工作结束,因为如果主线程先结束了,那子线程会因为没有可用资源而导致程序崩溃。
如果我们希望主线程结束了,子线程自行终止,那这时就要设置一下 Daemon 线程的属性了,设置之后,主线程若是想要结束运行,需要检查一下 Daemon 线程的属性。
如果 Daemon 线程的属性是 True,其它非 Daemon 线程执行结束,不会等待 Daemon 线程,主线程会自动结束。
如果 Daemon 线程属性是 False,那主线程必须等待 Daemon 线程结束才会将程序结束运行。
以上内容翻译成大白话就是可以把一个线程设置为 Daemon 线程,而且还可以设置一个属性,如果属性设置为 True,那该线程就不受重视了,其它线程结束,它就被结束了,如果设置为 False,那它就是最重要的了,主线程需要等着它结束运行,才可以进行下一步操作。
以上代码运行之后发现瞬间执行完毕了,并没有等待 5 秒钟,充分证明了不被重视的线程的处境。
接下来修改一个属性,可以再看一下效果。
运行之后发现程序等待 5 秒之后才结束运行,你是否发现了其中的差异呢?
15.1.5 堵塞主线程
主线程在工作的时候,如果希望子线程先运行,直到该子线程运行结束,主线程才继续工作。
join 方法可以增加一个参数,该参数表示等待的秒数,当秒数到了,主线程恢复工作。
15.1.6 is_alive 检验子线程是否在工作
使用 join 方法之后,一般在后面需要加上一个 is_alive
方法,该方法会简称子线程是否工作结束了,如果子线程结束则返回 False,仍在工作则会返回 True。
有的教程或者书籍中还会使用 isAlive
方法来进行判断,这是因为 Python 版本的问题,后续建议使用 is_alive
方法。
15.1.7 自定义线程类
threading.Thread
是 threading
模块内的一个类,我们可以继承这个类,定义自己的线程类,定义的时候有两个需要注意的地方,第一个需要在构造函数中调用 threading.Thread.init()
方法,第二个是需要在类内容定义好 run
方法。
之前的内容中,通过 threading.Thread
声明一个线程对象时,执行 start
方法可以建立一个线程,start
方法就是在调用类中的 run
方法。
15.1.8 资源锁定与解锁
在多线程程序中经常碰到多个线程使用一个共享资源的情况,为了确保共享资源在多线程共享时不出现问题,需要使用 theading.Lock
对象的两个方法 acquire
与 release
。
以上代码没有使用 acquire
与 release
方法,出现的结果无规律可循,是因为各线程无法预期谁会优先取得资源,专业描述叫做 线程以不可预知的速度向前推进
,当然有的地方叫做线程竞速,一个意思。
稍微修改一下就可以让线程按照规矩执行了,在使用全局变量的时候,先锁定资源,使用之后在释放资源。
以上内容如果使用 acquire
连续使用两次就会导致死锁。
关于死锁问题与资源锁定 Threading.RLock
,还有高级锁定相关的知识,在以后的滚雪球中继续学习,先阶段掌握基本的锁定就可以啦。
15.1.9 未来要学习的知识
进展到现在你已经可以实现简单的多线程开发了,但是对于线程类的学习只揭示了最简单的一部分,后续我们将学习到如下内容,都在第二遍滚雪球时学习。
queue 模块,也叫做队列模块
Semaphore 信号量,高级锁机制
Barrier 栅栏
Event 线程通讯机制
15.2 subprocess 模块
subprocess 是 Python 中用于建立子进程的模块,注意是子进程。导入该模块使用 import subprocess
。
15.2.1 Popen 方法
该方法可以打开计算机内部的应用程序,也可以打开自己写好的程序,文件路径写对即可。
打开的子进程,主程序已经结束了。
15.2.2 Popen 方法携带参数
可以在 Popen 方法打开程序的时候,传递一个参数进去,该参数为列表类型,第一个元素是要打开的应用程序,第二个则是传递进去的文件。
例如打开画图程序。
文件的路径不要写错,以上代码会打开画板程序并且在画板打开一个图片。
15.2.3 通过 start 打开程序
在电脑上通过双击就可以打开某种文件,这是因为 Windows 系统已经给我们做好了关联,那能不能在 Python 中也模拟出该方式呢,很简单,通过 subprocess.Popen
方法的参数即可实现。
使用该代码打开图片是使用你默认的图片预览程序,满足了刚才所说的场景。该方法核心使用的有两个地方一个是原程序位置使用的是 start
关键字(仅在 Windows 上有效),第一个是 shell = True
参数。
15.2.4 通过 run 方法调用子进程
该方法属于新增方法,通过 subprocess.run
方法即可调用子进程。具体内容可以自行尝试即可。
15.3 这篇博客的总结
本篇博客主要内容是 Python 的多线程应用,顺带着说了一点点关于进程的相关知识,对于多线程,很多学习 Python 很久的同学都不一定可以搞清楚,在这里希望大家第一次学习先有概念支撑即可,能掌握多少在本阶段不重要,学习是需要时间积累的,一遍就会那是天才或者是吹牛的,有很多工作 2~3 年的还不一定能把多线程多进程说清楚呢,所以不要着急哦,继续往后面看,往后面学就好了。
**
第一遍滚雪球学 Python 收官。下期见。
**
**想学 Python 爬虫,可以订阅橡皮擦专栏哦~
** 🈲🈲🈲🈲 点击发现惊喜 🈲🈲🈲🈲
🈚🈚🈚🈚🈚
如果你想跟博主建立亲密关系,可以关注同名公众号 <font color="red">梦想橡皮擦</font>,近距离接触一个逗趣的互联网高级网虫。
博主 ID:梦想橡皮擦,希望大家<font color="red">点赞</font>、<font color="red">评论</font>、<font color="red">收藏</font>。
版权声明: 本文为 InfoQ 作者【梦想橡皮擦】的原创文章。
原文链接:【http://xie.infoq.cn/article/bd926943a40b46479461abb67】。文章转载请联系作者。
评论