在python中单线程,多线程,多进程对CPU的利用率实测以及GIL原理分析
首先关于在python中单线程,多线程,多进程对cpu的利用率实测如下:
单线程,多线程,多进程测试代码使用死循环。
1)单线程:
2)多线程:
3)多进程:
查看cpu使用效率:
开始观察分别执行时候cpu的使用效率:
1)单线程执行的时候:
2)多线程执行的时候:
3)多进程执行的时候:
总结:
1)单进程单线程时,对于双核CPU的利用率只能利用一个核,没有充分利用两个核。
2)单进程多线程时,对于双核CPU的来说,虽然两个核都用到的,不过很明显没有充分利用两个核,这里要说一个GIL(全局解释器锁)的概念:
GIL不同于线程之间的互斥锁,GIL并不是Python的特性,而是Cpython引入的一个概念。(Jpython,PYPY)
Python的代码由Python的解释器执行(CPython)。那么我们的代码什么时候被python解释器执行,由我们的GIL也就是全局解释器锁进行控制。
当我们有一个线程开始访问解释器的时候,GIL会将这把锁上锁,也就是说,其他线程无法再访问解释器,也就意味着,其他的线程无法再被执行。
GIL执行流程:
-
加锁GIL。
-
切换到一个线程去执行。
-
运行。
-
解锁GIL。
再次重复以上步骤。
对于下列代码GIL的执行流程:
import threading
import time
# 写两个函数,分别让两个线程去执行
# 这个两个函数,都要访问我的全局变量
number = 0
def test1(count):
global number
for i in range(count):
number += 1
print(number)
def test2(count):
global number
for i in range(count):
number += 1
print(number)
def main():
th1 = threading.Thread(target=test1,args= (1000000,))
th2 = threading.Thread(target=test2, args=(1000000,))
th1.start()
th2.start()
time.sleep(5)
print(number)
if __name__ == '__main__':
main()
运行结果(这里充分的说明了多线程资源抢占问题):
流程图如下:
线程1在执行到对全局变量加一操作的时候全局解释器锁被收回,线程2申请并得到了全局解释器锁开始运行,在线程2执行完加一操作以后对全局变量进行了修改并释放了全局解释器锁。
这时线程1再次得到了全局解释器锁,从上次释放全局解释器锁的地方开始继续执行对全局变量加一的操作,记住,这里线程1中的全局变量还是开始的0,虽然线程2已经对其进行了加一的操作,但是线程1并不知道,线程1还是会接着上一次的位置开始执行,所以线程1在执行完加一操作的时候同样把1再次赋值给了全局变量num,也就是说,线程2执行完加一操作之后赋值过去的1又被线程1赋值过去的1所覆盖,加了两次等于加了一次!类似于协程,只是做了一个执行代码来回切换的操作!
所以在Python中,同一时刻,只能有一个线程被执行。所以Python中的多线程是假的。
既然这样我们为什么还要用多线程呢?
其实多线程也有它的好处,例如我们在进行IO操作的时候,有效的组织了程序的阻塞,不至于一直无限的等待。
3)多进程时,对于双核CPU来说,每个进程的优先级都是同等的,所分配的资源也是相等的,两个进程的时候完全可以充分的利用双核CPU,而且由于计算密集型的任务完全是依靠于cpu的核数,所以需要尽量的完全利用cpu,这时候多进程的好处就能够完美的体现出来。
------- 知识无价,汗水有情,如需搬运请注明出处,谢谢!
关注公众号
低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
-
上一篇
JavaScript 编程精解 中文第三版 十七、在画布上绘图
十七、在画布上绘图 原文:Drawing on Canvas 译者:飞龙 协议:CC BY-NC-SA 4.0 自豪地采用谷歌翻译 部分参考了《JavaScript 编程精解(第 2 版)》 绘图就是欺骗。 M.C. Escher,由 Bruno Ernst 在《The Magic Mirror of M.C. Escher》中引用 浏览器为我们提供了多种绘图方式。最简单的方式是用样式来规定普通 DOM 对象的位置和颜色。就像在上一章中那个游戏展示的,我们可以使用这种方式实现很多功能。我们可以为节点添加半透明的背景图片,来获得我们希望的节点外观。我们也可以使用transform样式来旋转或倾斜节点。 但是,在一些场景中,使用 DOM 并不符合我们的设计初衷。比如我们很难使用普通的 HTML 元素画出任意两点之间的线段这类图形。 这里有两种解决办法。第一种方法基于 DOM,但使用可缩放矢量图形(SVG,Scalable Vector Graphics)代替 HTML。我们可以将 SVG 看成文档标记方言,专用于描述图形而非文字。你可以在 HTML 文档中嵌入 SVG,还可以在<im...
-
下一篇
动态代理之: com.sun.proxy.$Proxy0 cannot be cast to 问题
Exception in thread "main" java.lang.ClassCastException: com.sun.proxy.$Proxy0 cannot be cast to Father.FatherInter at Father.Main.main(Main.java:13) 不知道写动态代理的时候 你们有没有被这个问题困扰过 反正我是有的 不过和网上的问题不一样 Google很多 答案都是 因为被代理的类没有继承接口 而是继承了一个基类 问:为什么动态代理必须针对接口? **答:**JDK动态代理的原理是根据定义好的规则,用传入的接口创建一个新类,这就是为什么采用动态代理时为什么只能用接口引用指向代理,而不能用传入的类引用执行动态类。(摘自网络 自己没有看源码) 我的 问题 则是因为 Son s = (Son)Proxy.newProxyInstance(si.getClass().getClassLoader(), si.getClass().getInterfaces(), m); 在我这里 Son是实现接口的实现类 这个时候就GG了 正解是 FatherI...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- CentOS7设置SWAP分区,小内存服务器的救世主
- Springboot2将连接池hikari替换为druid,体验最强大的数据库连接池
- SpringBoot2编写第一个Controller,响应你的http请求并返回结果
- CentOS7编译安装Cmake3.16.3,解决mysql等软件编译问题
- CentOS关闭SELinux安全模块
- Dcoker安装(在线仓库),最新的服务器搭配容器使用
- CentOS8编译安装MySQL8.0.19
- Windows10,CentOS7,CentOS8安装Nodejs环境
- SpringBoot2全家桶,快速入门学习开发网站教程
- Docker快速安装Oracle11G,搭建oracle11g学习环境














微信收款码
支付宝收款码