Python 的多线程是鸡肋?
“唉,还没毕业就受到甲方的支配,等以后进了公司可咋整啊。”小白嘴里这么吐槽,但心理上还是不敢怠慢,只能恋恋不舍地关掉眼前的游戏,打开了 Python 代码思考了起来。
“现在的程序是单线程的,那就用多线程模型来优化吧,嘿嘿,我太机智了!”小白打心底感谢前段时间里学习到的线程的知识。“Python 里好像是 threading
模块负责多线程的,就决定是你了,threading
!”
花了两三个小时,小白终于把程序改好了,他长舒一口气,点击 Run
,开始测试运行时间。
“woc!怎么运行时间还变长了?”看着屏幕上显示的测试结果,小白傻眼了,这多线程怎么不顶用?自己明明是按官方文档来的啊!
debug 无果,小白只好寻求好朋友小明的帮助。
“哈哈哈,你居然用 python 的多线程?你不知道 **python 的多线程被很多人称作「鸡肋」**吗?”
“啊,不会吧?还有这种说法?我要是知道我肯定就不用多线程来改了。。。可为什么 python 的多线程就鸡肋了?那多线程爬虫是怎么回事?”
“我先给你解释下 python 下的多线程是怎么一回事吧。Python 是一门解释型语言,它的执行是由解释器来控制的,我们一般都会使用默认的 Cpython
解释器,这些我想你应该清楚。”
“那当然,这在一开始学 Python 的时候老师就讲过了。”
“那你知不知道什么是 GIL?”小明问道。
小白挠挠头,尴尬的回答:“我没听说过。”
“也是,你要是知道 GIL ,就能弄明白 Python 的多线程了。GIL,全称是 Global Interpreter Lock
,全局解释锁 ,专门给解释器用的。”
“蛤?解释器还要需要锁? ”
“这个锁别有妙用,让我先考考你,C 语言能不能在用户态下做到线程级别的时间片轮转?”
“不能!操作系统里讲过了,我还记得上次你教我的内容~”小白得意的回答。
关于线程,详细的在这里:https://my.oschina.net/u/4198159/blog/3115533
“但是 python 能做到!python 里,解释器可以记录每一个线程执行了多长时间——时间一到,就能够切换到另一条线程。”
“有点意思,听起来像是解释器充当了操作系统的角色,然后为 python 线程提供了时间片轮转的能力。”
tobe 注:理论上 C 语言也可以做到,毕竟 python 解释器就是用 C 语言写的。
“解释的很到位,我再说回 GIL 吧,在多核还没有出现的时候,就已经有线程的存在了,GIL 就是拿来给线程加锁的,当一个线程将要执行时,解释器会把 GIL 锁给这个线程,其他线程因为没有锁,是无法运行的。等到持有锁线程阻塞或者运行 100 个字节码,解释器就会把锁交给其他线程。”
“但是这个 GIL 锁是全局(Global)的,也就导致即使是多核情况下,一次也只有一个线程能运行,从整体上看,整个程序是串行的。”
小白恍然大悟:“怪不得我的程序还变慢了,原来 python 的多线程不仅不能利用多核,还因为线程切换拖慢了我程序的执行速度!我想很多人应该都遇到过我这个问题吧,Python 社区为什么不修改这一特性,让多线程也做到并行呢?”
小明叹了口气:“哪有这么简单,修改锁的设计是很难的,我听说 MYSQL 拆分 buffer pool mutex
这个全局锁花了好多年呢。不过 Python 社区为此还是做了不少挽救工作的,比如**在线程睡觉(sleep),等待连接的时候主动释放 GIL,让其他线程继续执行。**拿爬虫程序来说吧,单个爬虫总会花时间在下载网页上,很多 CPU 时间就浪费掉了, 提供 sleep 机制后,这些爬虫可以在等待下载时释放 GIL 锁,把机会让给其他爬虫,这样整体运行速度能够得到大幅提升。”
“我好像明白了,”小白感觉自己被打通了任督二脉:“也就是说 Python 的多线程适合 I/O 密集型的程序,但是对计算密集型程序就不那么友好了~ 诶等等,那我怎么办?我还打算用多线程优化我的程序呢!”
“让 python 利用多核的方法还是有的,比如说,让 python 调用 C 语言的代码,在 C 语言里实现多线程,因为 C 语言里没有 GIL 锁,这些线程不会受到 GIL 的约束,也就能并行了。”
小白一个劲儿摇头:“不不不不不,好不容易写完的 Python 代码,你让我改成 C?这不是要我的命吗!我拒绝!”
“这不是还有第二种方法嘛——使用多进程,Python 里有个 multiprocessing
模块,可以创建多个进程,因为不同的进程使用不同的解释器,所以它们有各自的 GIL,互不干扰,自然就能完成并发了。“
“这个方法听起来才正常嘛,我马上就回去试试,谢谢你了!”
希望你在看完我的文章之后有所收获~(求点赞呐!)

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
解决Angular CLI找不到模块"angular-devkit/build-angular"的问题
Angular CLI 是 Angular 客户端命令行工具,提供非常多的命令来简化 Angular 的开发。今天执行“ng serve”命令时,竟然报找不到模块"@angular-devkit/build-angular"的错误。 问题背景 执行“ng serve”命令时,竟然报找不到模块"@angular-devkit/build-angular"的错误。信息如下: >ng serve An unhandled exception occurred: Could not find module "@angular-devkit/build-angular" from "D:\\workspaceGithub\\mean-news-ui\\mean-news-ui". See "C:\Users\LYF\AppData\Local\Temp\ng-FStMRr\angular-errors.log" for further details. 解决 怀疑是 Angular CLI 与 Angular 应用版本不匹配或者是本地环境有错误引起的。 解决的方案就是卸载 Angular ...
- 下一篇
GitLab 12.4.1, 12.3.6, 12.2.9 发布,重要安全更新
Gitlab 又又又发布了重要的安全更新补丁 12.4.1, 12.3.6, 和 12.2.9 ,包括社区版和企业版。包含重要的安全更新,强烈建议所有 Gitlab 用户立即更新!!! 存在的安全漏洞编号CVE-2019-18446,影响GitLab CE/EE 8.15 以及以后的所有版本! 该安全漏洞会导致未授权的用户删除合并请求分支。 此外还有CVE-2019-18447,该漏洞会导致私有组的成员泄露,该漏洞影响之前的所有版本!!! 还有其他的漏洞(请看这里)例如私有项目名泄露等等,我就懒得一一赘述了,反正安全漏洞很多,你自己看着办。 ------ 如果嫌麻烦,不妨用 gitee.com,安全又省事。
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- CentOS7设置SWAP分区,小内存服务器的救世主
- CentOS8,CentOS7,CentOS6编译安装Redis5.0.7
- 设置Eclipse缩进为4个空格,增强代码规范
- Docker使用Oracle官方镜像安装(12C,18C,19C)
- SpringBoot2全家桶,快速入门学习开发网站教程
- Jdk安装(Linux,MacOS,Windows),包含三大操作系统的最全安装
- SpringBoot2初体验,简单认识spring boot2并且搭建基础工程
- MySQL8.0.19开启GTID主从同步CentOS8
- SpringBoot2更换Tomcat为Jetty,小型站点的福音
- CentOS8编译安装MySQL8.0.19