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

新服务器做网站怎么自己做免费网站

新服务器做网站,怎么自己做免费网站,厦门哪家网站建设最好,一站式网站建设顾问深入理解Python中的全局解释锁GIL 转自#xff1a;https://zhuanlan.zhihu.com/p/75780308 注#xff1a;本文为蜗牛学院资深讲师卿淳俊老师原创#xff0c;首发自公众号https://mp.weixin.qq.com/s/TBiqbSCsjIbNIk8ATky-tg#xff0c;如需转载请私聊我处获得授权并注明出处…深入理解Python中的全局解释锁GIL 转自https://zhuanlan.zhihu.com/p/75780308 注本文为蜗牛学院资深讲师卿淳俊老师原创首发自公众号https://mp.weixin.qq.com/s/TBiqbSCsjIbNIk8ATky-tg如需转载请私聊我处获得授权并注明出处。 Python是门古老的语言要想了解这门语言的多线程和多进程以及协程以及明白什么时候应该用多线程什么时候应该使用多进程或协程我们不得不谈到的一个东西是Python中的GIL全局解释器锁。这篇我们就来看看这个GIL究竟是怎么回事。 1. GIL是什么 首先来看看GIL究竟是什么。我们需要明确的一点是GIL并不是Python的特性它是在实现Python解析器(CPython)时所引入的一个概念。就好比C是一套语言语法标准但是可以用不同的编译器来编译成可执行代码。有名的编译器例如GCCINTEL CVisual C等。Python也一样同样一段代码可以通过CPythonPyPyPsyco等不同的Python执行环境来执行。像其中的JPython就没有GIL。然而因为CPython是大部分环境下默认的Python执行环境。所以在很多人的概念里CPython就是Python也就想当然的把GIL归结为Python语言的缺陷。所以这里要先明确一点GIL并不是Python的特性Python完全可以不依赖于GIL。 那么CPython实现中的GIL又是什么呢GIL全称Global Interpreter Lock为了避免误导我们还是来看一下官方给出的解释 In CPython, the global interpreter lock, or GIL, is a mutex that prevents multiple native threads from executing Python bytecodes at once. This lock is necessary mainly because CPython’s memory management is not thread-safe. (However, since the GIL exists, other features have grown to depend on the guarantees that it enforces.) 这看起来像一个Bug一般的防止多线程并发执行机器码的互斥锁(mutex)究竟为什么会存在 2. GIL为什么会存在 GIL的问题其实是由于近十几年来应用程序和操作系统逐步从多任务单核心演进到多任务多核心导致的 , 在一个古老的单核CPU上调度多个线程任务大家相互共享一个全局锁谁在CPU执行谁就占有这把锁直到这个线程因为IO操作或者Timer Tick到期让出CPU没有在执行的线程就安静的等待着这把锁除了等待之外他们应该也无事可做。下面这个图演示了一个单核CPU的线程调度方式 很明显在一个现代多核心的处理器上上面的模型就有很大优化空间了原来只能等待的线程任务现在可以在其它空闲的核心上调度并发执行。由于古老GIL机制如果线程2需要在CPU 2 上执行它需要先等待在CPU 1 上执行的线程1释放GIL记住GIL是全局的。如果线程1是因为 i/o 阻塞让出的GIL那么线程2必定拿到Gil。但如果线程1是因为timer ticks计数满100让出GIL那么这个时候线程1和线程2公平竞争。但要命的是在Python 2.x, 线程1不会动态的调整自身的优先级所以很大概率下次被选中执行的还是线程1在很多个这样的选举周期内线程2只能安静的看着线程1拿着GIL在CPU 1上欢快的执行。 在稍微极端一点的情况下比如线程1使用了while True在CPU 1 上执行那就真是“一核有难八核围观”了如下图所示 接下来我们用实际代码来看看GIL的存在对多线程运行的影响此处使用循环模拟耗时操作 # coding:utf-8 import threading, timedef my_counter():i 0for _ in range(100000000):i i1return Truedef main1():thread_ary {}start_time time.time()for tid in range(2):t threading.Thread(targetmy_counter)t.start()t.join() # 第一次循环的时候join方法引起主线程阻塞但第二个线程并没有启动所以两个线程是顺序执行的print(单线程顺序执行total_time: {}.format(time.time() - start_time))def main2():thread_ary {}start_time time.time()for tid in range(2):t threading.Thread(targetmy_counter)t.start()thread_ary[tid] tfor i in range(2):thread_ary[i].join() # 两个线程均已启动所以两个线程是并发的print(并发执行total_time: {}.format(time.time() - start_time))if __name__ __main__:main1()main2()上面这段代码在Python3上运行不管是并发执行还是顺序执行运行时间都差不多这充分说明了GIL确实会在这种情况下对多线程程序的运行效率产生影响。如果是在Python2上运行则差距更明显。 Python3.6上运行的结果Python2.7上运行的结果Python3.2以后对GIL做了较大的优化 3. GIL是否意味着线程安全 有GIL并不意味着python一定是线程安全的那什么时候安全什么时候不安全我们必须搞清楚。之前我们已经说过一个线程有两种情况下会释放全局解释器锁一种情况是在该线程进入IO操作之前会主动释放GIL另一种情况是解释器不间断运行了1000字节码Py2或运行15毫秒Py3后该线程也会放弃GIL。既然一个线程可能随时会失去GIL那么这就一定会涉及到线程安全的问题。GIL虽然从设计的出发点就是考虑到线程安全但这种线程安全是粗粒度的线程安全即不需要程序员自己对线程进行加锁处理同理所谓细粒度就是指程序员需要自行加、解锁来保证线程安全典型代表是 Java , 而 CPthon 中是粗粒度的锁即语言层面本身维护着一个全局的锁机制,用来保证线程安全。那么什么时候需要加锁什么时候不需要加锁这个需要具体情况具体分析。下面我们就来针对每种可能的情况进行分析和总结。 首先来看第一种线程释放GIL的情况。假设现在线程A因为进入IO操作而主动释放了GIL那么在这种情况下由于线程A的IO操作等待时间不确定那么等待的线程B一定会得到GIL锁这种比较“礼貌的”情况我们一般称为“协同式多任务处理”相当于大家按照协商好的规则来线程是安全的不需要额外加锁。 接下来我们来看另外一种情况即线程A是因为解释器不间断执行了1000字节码的指令或不间断运行了15毫秒而放弃了GIL那么此时实际上线程A和线程B将同时竞争GIL锁。在同时竞争的情况下实际上谁会竞争成功是不确定的一个结果所以一般被称为“抢占式多任务处理”这种情况下当然就看谁抢得厉害了。当然在python3上由于对GIL做了优化并且会动态调整线程的优先级所以线程B的优先级会比较高但仍然无法肯定线程B就一定会拿到GIL。那么在这种情况下线程可能就会出现不安全的状态。针对这种纯计算的操作我们用一段代码来演示下这种线程不安全的状态。代码如下 import threadingn 0def add():global nfor i in range(1000000):n n 1def sub():global nfor i in range(1000000):n n - 1if __name__ __main__:t1 threading.Thread(targetadd)t2 threading.Thread(targetsub)t1.start()t2.start()t1.join()t2.join()print(n , n)上面的代码很简单分别用线程1和线程2对全局变量n进行了1000000次的加和减操作。如果线程安全的话那么最终的结果n应该还是为0。但实际上我们运行之后会发现这个n的值有时大有时小完全不确定。这就是典型的多个线程操作同一个全局变量造成的线程不安全的问题。我们明白了这个问题在这里我们只讨论产生问题的原因在后面的文章中再来讨论如何通过加锁来解决这个问题。 接下来我们从代码层面分析下产生这个问题的原因。在线程中我们主要是执行了一个加法和减法的操作。为了方便说明问题我们把函数最简化到一个加法函数和一个减法函数来分析它们的字节码执行过程来看看释放GIL锁是怎么引起这个问题的。演示代码如下 import dis n 0def add():global nn n 1print(dis.dis(add))def sub():global nn n - 1 print(dis.dis(sub))dis模块中的dis方法可以打印出一个函数对应的字节码执行过程所以非常方便我们进行分析。运行结果如下 不管是加法还是减法运算都会分为4步完成。以加法为例第一步是LOAD_GLOBAL(加载全局变量n)第二步LOAD_CONST(加载常量1)第三步进行二进制的加法第四步将计算结果存储到全局变量n中加法计算结束。这四个指令如果能够保证被作为一个整体完整地运行那么是不会产生问题的但根据前面说的线程释放GIL的原则那么很有可能在线程正在执行这四步中的任何一步的时候释放掉GIL而进入等待状态这个时候发生的事情就比较有意思了。为了方便大家理解我拿一种比较极端的情况来说明一下。比如我们在加法运算中正准备执行第四步的时候很不幸失去了GIL进入等待状态注意此时n值仍然为0。减法运算的线程开始执行它加载了全局变量n值为0并进行减法相关的计算它也在执行第三步的时候失去了GIL此时它进入等待状态加法运算继续。上一次加法计算继续运行第4步即把加法运算结果赋值给全局变量n那么此时n的值为1。同样道理减法操作拿回GIL时它之前已经加载了为0的n的值所以它继续操作到最后赋值那步时n的值就为0-1-1。换句话说n的值要么为1要么为-1但我们期望的应该是0。这就造成了线程不安全的情形。最终经过百万次这样不确定的加减操作那么结果一定是不确定的。这就是引起这个问题的过程和原因。 接下来我们还要解决另外一个问题也就是既然GIL从粗粒度情况下存在线程不安全的可能性那么是不是所有非IO操作引起的GIL释放都要加锁来解决线程安全的问题。这个问题同样要分情况因为python跟其他线程自由的语言比如 Java相比它有很多操作是原子级的针对原子级的操作由于方法本身是单个字节码所以线程没有办法在调用期间放弃GIL。典型的例子比如sort方法我们同样可以看看这种原子级的操作在python的字节码中是什么样子代码演示如下 import dislst [4, 1, 3, 2]def foo():lst.sort()print(dis.dis(foo))运行后结果如下 从字节码的角度调用sort操作是原子级无法再分的所以线程不会在执行期间发生GIL释放的情况也就是说我们可以认为sort操作是线程安全的不需要加锁。而我们上面演示的加法和减法操作则不是原子级的所以我们必须要加锁才能保证线程安全。 所以总结一下如果多线程的操作中不是IO密集型并且计算操作不是原子级的操作时那么我们需要考虑线程安全问题否则都不需要考虑线程安全。当然为了避免担心哪个操作是原子的我们可以遵循一个简单的原则始终围绕共享可变状态的读取和写入加锁。毕竟在 Python 中获取一个 threading.Lock 也就是一行代码的事。 4. 如何避免GIL的影响 有两个建议 在以IO操作为主的IO密集型应用中多线程和多进程的性能区别并不大原因在于即使在Python中有GIL锁的存在由于线程中的IO操作会使得线程立即释放GIL切换到其他非IO线程继续操作提高程序执行效率。相比进程操作线程操作更加轻量级线程之间的通讯复杂度更低建议使用多线程。 如果是计算密集型的应用尽量使用多进程或者协程来代替多线程。
http://www.huolong8.cn/news/487922/

相关文章:

  • html5网站模板怎么修改网站建立的方式是什么
  • 自己做的网站转成二维码什么是个人网站
  • 游戏网站开发协议免费域名申请网站大全推荐
  • 网站群发软件企业网站设计方案书
  • 网站建设存在问题软件开发项目名称
  • 网站导航条内容深圳招聘网站
  • 重庆 手机网站制作重庆网站推广步骤
  • 北京营销型网站建设价格西安好玩的地方有哪些
  • 如何使用网站模板网站开发7个基本流程
  • 医院网站建设需求分析调研表广东网站建设公
  • 制作网站哪家好高质量摄影作品网站
  • php网站开发的技术框架无极任务平台网站进入
  • 广州网站建设改版门户网站的建设意义
  • 贵阳微网站建设wordpress弹窗公告
  • 可以做设计的网站高平网站建设
  • 无锡市网站建设网站建设服务协议 百度
  • 班级网站设计怎么用wordpress仿站
  • 企业网站开发公司排行榜制作企业网站页面实训项目
  • 扁平化网站设计趋势做理财的网站有哪些内容
  • 网站建设 豫icp备揭阳网站建站网站
  • 三五互联网站管理登录地址人力资源招聘网站建设方案
  • 如何在个人网上建网站网站客户端开发
  • 厦门高端网站建设公最好玩的网游排名前十
  • 外贸网站每天多少ip崇左北京网站建设
  • 如何用rp做网站步骤网站seo方案建设目标
  • 微信商城和微网站国外网站推广平台有哪些?
  • 上海网站排名提升做外贸网站咨询
  • 企业网站建设商城运城手机网站制作
  • 网站管理助手4.0破解wordpress禁止搜索代码
  • seo网站优化排名建站平台 phpwind