当前位置: 首页 > news >正文

Python GIL(Global Interpreter Lock)

一、GIL介绍
GIL本质就是一把互斥锁,既然是互斥锁,所有互斥锁的本质都一样,都是将并发运行变成串行,以此来控制同一时间内共享数据只能被一个任务所修改,进而保证数据安全。
可以肯定的一点是:保护不同的数据的安全,就应该加不同的锁。
要了解GIL,首先确定一点:每次执行python程序,都会产生一个独立的进程。例如python test.py,python aaa.py,python bbb.py会产生3个不同的python进程
在一个python的进程内,不仅有test.py的主线程或者由该主线程开启的其他线程,还有解释器开启的垃圾回收等解释器级别的线程,总之,所有线程都运行在这一个进程内。
1、所有数据都是共享的
    其中代码作为一种数据也是被所有线程共享的(test.py的所有代码以及Cpython解释器的所有代码)
2、所有线程的任务,都需要将任务的代码当做参数传给解释器的代码去执行,即所有的线程要想运行自己的任务,首先需要解决的是能够访问到解释器的代码
 综上:
    如果多个线程的target=work,那么执行流程是
    多个线程先访问到解释器的代码,即拿到执行权限,然后将target的代码交给解释器的代码去执行
解释器的代码是所有线程共享的,所以垃圾回收线程也可能访问到解释器的代码而去执行,这就导致了一个问题:
    对于同一个数据100,可能线程1执行x=100的同时,而垃圾回收执行的是回收100的操作,解决这种问题没有什么高明的方法?
    就是加锁处理,如下图的GIL,保证python解释器同一时间只能执行一个任务的代码

二、GIL与Lock
GIL保护的是解释器级的数据,保护用户自己的数据则需要自己加锁处理,如下图

Python GIL(Global Interpreter Lock)
Python GIL(Global Interpreter Lock)

三、GIL与多线程
有了GIL的存在,同一时刻同一进程中只有一个线程被执行
进程可以利用多核,但是开销大,而python的多线程开销小,但却无法利用多核优势,要解决这个问题,我们需要在几个点上达成一致:
    1. cpu到底是用来做计算的,还是用来做I/O的?
    2. 多cpu,意味着可以有多个核并行完成计算,所以多核提升的是计算性能
    3. 每个cpu一旦遇到I/O阻塞,仍然需要等待,所以多核对I/O操作没什么用处 
一个工人相当于cpu,此时计算相当于工人在干活,I/O阻塞相当于为工人干活提供所需原材料的过程,工人干活的过程中如果没有原材料了,则工人干活的过程需要停止,直到等待原材料的到来。
如果你的工厂干的大多数任务都要有准备原材料的过程(I/O密集型),那么你有再多的工人,意义也不大,还不如一个人,在等材料的过程中让工人去干别的活,
反过来讲,如果你的工厂原材料都齐全,那当然是工人越多,效率越高
结论:
    对计算来说,cpu越多越好,但是对于I/O来说,再多的cpu也没用
    当然对运行一个程序来说,随着cpu的增多执行效率肯定会有所提高(不管提高幅度多大,总会有所提高),这是因为一个程序基本上不会是纯计算或者纯I/O,所以我们只能相对的去看一个程序到底是计算密集型还是I/O密集型,从而进一步分析python的多线程到底有无用武之地。
假设一种情况:
    现在有四个任务需要处理,处理方式是要有并发的效果,解决方案可以是:
    方案一:开启四个进程
    方案二:一个进程下,开启四个线程
    单核情况下,分析结果: 
        如果四个任务是计算密集型,没有多核来并行计算,方案一徒增了创建进程的开销,方案二胜
        如果四个任务是I/O密集型,方案一创建进程的开销大,且进程的切换速度远不如线程,方案二胜
    多核情况下,分析结果:
        如果四个任务是计算密集型,多核意味着并行计算,在python中一个进程中同一时刻只有一个线程执行用不上多核,方案一胜
        如果四个任务是I/O密集型,再多的核也解决不了I/O问题,方案二胜
结论:
    现在的计算机基本上都是多核,python对于计算密集型的任务开多线程的效率并不能带来多大性能上的提升,甚至不如串行(没有大量切换)
    但是,对于IO密集型的任务效率还是有显著提升的。

四、多线程性能测试
1、计算密集型:多进程效率高
    from multiprocessing import Process
    from threading import Thread
    import os,time
    def work():
            res=0
            for i in range(100000000):
                    res*=i
    l=[]
    print(os.cpu_count()) #本机为4核
    start=time.time()
    for i in range(4):
            # p=Process(target=work) #耗时18s多
            p=Thread(target=work) #耗时26s多
            l.append(p)
            p.start()
    for p in l:
            p.join()
    stop=time.time()
    print('run time is %s' %(stop-start))
2、i/o密集型:多线程效率高
    from multiprocessing import Process
    from threading import Thread
    import threading
    import os,time
    def work():
            time.sleep(2)
            print('===>')
    l=[]
    print(os.cpu_count()) #本机为4核
    start=time.time()
    for i in range(400):
            p=Process(target=work) #耗时4s多,大部分时间耗费在创建进程上
            # p=Thread(target=work) #耗时2s多
            l.append(p)
            p.start()
    for p in l:
            p.join()
    stop=time.time()
    print('run time is %s' %(stop-start))
应用:
多线程用于IO密集型,如socket,爬虫,web
多进程用于计算密集型,如金融分析

转载于:https://blog.51cto.com/10630401/2073564

相关文章:

  • blend4web的三维小场景的开发应用(2)
  • 前端面试题整理汇总
  • 如何优雅的在手机上进行Python编程
  • TiDB 源码阅读系列文章(一)序
  • 小程序开发 Wepy 框架 使用规范
  • 傲娇的性格、逗比的语气,和聊天机器人谈情说爱可行吗?
  • 自己简单写的 事件订阅机制
  • ReactNative从零到完整项目-state使用详解
  • 150行实现Promise 90%的功能
  • PlaNet图片识别机器,准确表现超过人类
  • 精选15个国外CSS框架
  • python基础—条件语句
  • 【391天】每日项目总结系列128(2018.03.03)
  • 有货移动Web端性能优化探索实践
  • 修复.NET的HttpClient
  • 08.Android之View事件问题
  • Android路由框架AnnoRouter:使用Java接口来定义路由跳转
  • Android系统模拟器绘制实现概述
  • GraphQL学习过程应该是这样的
  • Hexo+码云+git快速搭建免费的静态Blog
  • JAVA 学习IO流
  • Joomla 2.x, 3.x useful code cheatsheet
  • Js基础知识(一) - 变量
  • Leetcode 27 Remove Element
  • leetcode386. Lexicographical Numbers
  • MQ框架的比较
  • PHP 使用 Swoole - TaskWorker 实现异步操作 Mysql
  • win10下安装mysql5.7
  • 从0到1:PostCSS 插件开发最佳实践
  • 模型微调
  • 前端技术周刊 2018-12-10:前端自动化测试
  • 在 Chrome DevTools 中调试 JavaScript 入门
  • ​油烟净化器电源安全,保障健康餐饮生活
  • #QT(串口助手-界面)
  • (1)Map集合 (2)异常机制 (3)File类 (4)I/O流
  • (Forward) Music Player: From UI Proposal to Code
  • (附源码)ssm旅游企业财务管理系统 毕业设计 102100
  • (力扣记录)1448. 统计二叉树中好节点的数目
  • (已解决)报错:Could not load the Qt platform plugin “xcb“
  • (转)Oracle存储过程编写经验和优化措施
  • *p=a是把a的值赋给p,p=a是把a的地址赋给p。
  • .NET 6 在已知拓扑路径的情况下使用 Dijkstra,A*算法搜索最短路径
  • .NET Core WebAPI中封装Swagger配置
  • .NET MVC之AOP
  • .NET Remoting Basic(10)-创建不同宿主的客户端与服务器端
  • .Net Web项目创建比较不错的参考文章
  • .net 无限分类
  • .Net 应用中使用dot trace进行性能诊断
  • @ModelAttribute注解使用
  • @NoArgsConstructor和@AllArgsConstructor,@Builder
  • @reference注解_Dubbo配置参考手册之dubbo:reference
  • [ C++ ] STL_list 使用及其模拟实现
  • [ vulhub漏洞复现篇 ] Django SQL注入漏洞复现 CVE-2021-35042
  • [20190401]关于semtimedop函数调用.txt
  • [Android Studio 权威教程]断点调试和高级调试