zoukankan      html  css  js  c++  java
  • Python-为什么产生了GIL锁?

    因为在python设计出来的年代根本就没有多核这一说法,都是单核cpu,因为线程是cpu执行的最小单位,在单核情况下,我们的python进程中就算开了多条线程,在同一个时刻也只有一个线程被cpu调度执行,当某一个线程在执行时,其他线程都是停止工作的,所以不会同时对一个数据进行操作导致数据混乱。

    但是随着发展,出现了多核cpu,那么多个cpu就能执行多条线程,而我们的python解释器是一个进程,在进程中,线程是数据共享的。假设现在cpu1运行线程1,cpu2运行线程2,如果线程1与线程2正好都需要对同一个变量进行操作,就会产生并发数据不安全的问题。(上面不会出现数据安全问题是因为只有一个cpu,也就只有一条线程在运行。不会出现多条线程同时操作一个数据)。所以龟叔想了一个办法,就在cpython解释器上加了一把互斥锁,也就是GIL,在cpython解释器中,必须要获得这把互斥锁,线程才能被调度执行,这就又保证了在同一情况,只有拿到锁的那个线程会被运行,保证了数据安全,也就是只有一个cpu在运行。这就是大家诟病的cpython慢的原因,因为GIL锁是互斥锁,只能被一个线程获得,那么cpu再多也没用了,因为抢不到锁就得等着,这就是cpython无法利用多核优势的原理。

    后来龟叔一看,这样性能太差不行啊,所以他允许开多进程,开了多个进程那么就有多个python解释器进程,可以有多个GIL锁,也就可以有多个线程同时执行,并且因为进程之间是数据隔离的,也就不会产生数据混乱的问题。(首先进程间数据隔离了,不会相互改,并且在各自的进程中又有GIL锁,又保证各个线程数据的安全)。

    本人在这里产生了一个问题,就是在一个线程中,当我们定义一个变量,比如a=1时候,我们知道,python定义一个变量,是先产生一个a放在栈区,然后在堆区产生数据1,然后把对应关系建立,此时a的引用计数才为1,那么如果当我们在a刚产生的时候,线程的时间片正好到了,那么此时a的引用计数为0,这个线程的GIL锁释放,又正好被垃圾回收线程抢到了,按照垃圾回收的原理,a应该被回收,那么GIL锁不是就无法保护我们的数据安全了吗?

    其实答案很简单,因为在python在,变量的定义与赋值是一个原子性操作,原子性操作是不会被中断的,他不会被cpu的线程调度打断,即如果他开始了,那么一直到他结束,cpu都不会让出他的执行。所以也就不会产生上述的问题,其实在python中,有大量的原子性操作,即使像字典和类成员赋值这样的操作也是原子性。

  • 相关阅读:
    跨平台的好处
    Java生成PDF的另一种方法
    关于如何写小说的文章
    对概念解释得很好的文章列表
    k8s 添加补全脚本
    ingress与ingress-controller
    k8s 暴露服务的几种方式
    DevOps 的生活很有意思但并不容易---《DevOps 实践》读后总结 ----------转载转载转载转载转载转载转载转载转载
    SpringMVC的注解机制:Java中利用反射查找使用指定注解的类---找到指定包下的指定注解类
    Web应用安全威胁与防治--基于OWASP TOP 10 与ESAPI
  • 原文地址:https://www.cnblogs.com/chiyun/p/14066030.html
Copyright © 2011-2022 走看看