1. '''
  2. 定义:
  3. In CPython, the global interpreter lock, or GIL, is a mutex that prevents multiple
  4. native threads from executing Python bytecodes at once. This lock is necessary mainly
  5. because CPython’s memory management is not thread-safe. (However, since the GIL
  6. exists, other features have grown to depend on the guarantees that it enforces.)
  7. '''
    结论:在Cpython解释器中,同一个进程下开启的多线程,同一时刻只能有一个线程执行,无法利用多核优势

 前言: 

  1. - GIL其实就是一把互斥锁(牺牲了效率但是保证了数据的安全)。
  2. - 线程是执行单位,但是不能直接运行,需要先拿到python解释器解释之后才能被cpu执行
  3. - 同一时刻同一个进程内多个线程无法实现并行,但是可以实现并发

  一.GIL全局解释器 垃圾回收机制:

  1. - 垃圾回收机制也是一个任务,跟你的代码不是串行运行,如果是串行会明显有卡顿
  2. - 这个垃圾回收到底是开进程还是开线程?肯定是线程,线程肯定也是一段代码,所以想运行也必须要拿到python解释器
  3. 没有GIL全局解释器锁 他只是对线程加锁 不是对数据
  4. 运行垃圾回收机制:引用计数 1,必须先拿到python 解释器---> 2.python 进程下的多个线程是并发。若此时你想创建一个 a = 1 cpu运行速度是非常快的
    那么就会引发 其他线程垃圾回收机制扫描把我刚创建的内存清理掉 所以必须设置GIL全局解释器锁
    也就意味着在Cpython解释器上有一把GIL全局解释器锁

 二. 

  1. 1.python中的多线程到底有没有用?
      一、数据密集型
      二、IO密集型
  1. #### 1.python中的多线程到底有没有用?
  2.  
  3. 单核情况下:四个任务
  4.  
  5. 多核情况下:四个任务
  6.  
  7. 计算密集型:一个任务算十秒,四个进程和四个线程,肯定是进程快
  8.  
  9. IO密集型:任务都是纯io情况下,线程开销比进程小,肯定是线程好
  1. 一、数据密集型
    def task():
  2. res = 0
  3. for i in range(100000000):
  4. res = res*i
  5.  
  6. if __name__ == '__main__':
  7. print(os.cpu_count()) #本机内核
  8. p_list=[]
  9. start_time= time.time()
  10. for i in range(4):
  11. p = Process(target=task) # 进程运行时间为10.636553287506104
  12. # p = Thread(target= task) # 线程运行时间为19.97660756111145
  13. p.start()
  14. p_list.append(p)
  15. for p in p_list:
  16. p.join()
  17. end_time = time.time()
  18. print('运行时间为%s'% (end_time-start_time))

  

  1. ""
  2. 二、IO密集型
  3. def work():
  4. time.sleep(3)
  5. if __name__ == '__main__':
  6. print(os.cpu_count())
  7. start_time =time.time()
  8. p_list=[]
  9. for i in range(4):
  10. # p = Process(target= work) # run is total_time7.271259546279907
  11. p = Thread(target= work) # run is total_time3.002392053604126
  12. p.start()
  13. p_list.append(p)
  14. for p in p_list:
  15. p.join()
  16. end_time =time.time()
  17. print('run is total_time%s'%(end_time-start_time))

  三、全局锁与普通锁

  

  1. 对于不同的数据,要想保证安全,需要加不同的锁处理
  2. GIL并不能保证数据的安全,它是对Cpython解释器加锁,针对的是线程
  3. 保证的是同一个进程下多个线程之间的安全

  

  1. """
  2. from threading import Thread
  3.  
  4. import os
  5. import time
  6. from threading import Lock
  7. mutex = Lock()
  8. num = 100
  9. def task():
  10. global num
  11. mutex.acquire() #抢锁
  12. temp = num
  13. time.sleep(0.1)
  14. num = temp-1
  15. mutex.release() # 释放锁 开始一个
  16.  
  17. if __name__ == '__main__':
  18. p_lsit=[]
  19. for i in range(10):
  20.  
  21. p = Thread(target=task)
  22. p.start()
  23. p_lsit.append(p)
  24. for p in p_lsit:
  25. p.join()
  26. print(num) # 90 相当于10个线程同时去抢100票 必须要确保一个数据同时被10个进程同时抢 锁是起到保护作用 取完一个减一个

  四、.死锁与递归锁(了解)

自定义锁一次acquire必须对应一次release,不能连续acquire

递归锁可以连续的acquire,每acquire一次计数加一

  1. import time
  2. from threading import Thread,RLock
  3.  
  4. mutexA = mutexB= RLock() # 递归锁RLock
  5. class Mythread(Thread):
  6.  
  7. def run(self):
  8. self.fn1()
  9. self.fn2()
  10.  
  11. def fn1(self):
  12. #设置锁
  13. mutexA.acquire()
  14. print('%s 抢到A锁了'%self.name)
  15. mutexB.acquire()
  16. print('%s 抢到B锁了'%self.name)
  17. mutexB.release()
  18. print('%s释放了B锁'%self.name)
  19. mutexA.release()
  20. print('%s释放了A锁'%self.name)
  21.  
  22. def fn2(self):
  23. mutexB.acquire()
  24. print('%s 抢到A锁了' % self.name)
  25. time.sleep(1)
  26. mutexA.acquire()
  27. print('%s 抢到B锁了' % self.name)
  28. mutexA.release()
  29. print('%s释放了B锁' % self.name)
  30. mutexB.release()
  31. print('%s释放了A锁' % self.name)
  32.  
  33. if __name__ == '__main__':
  34. for i in range(100):
  35. t = Mythread()
  36. t.start()

  

五.Event事件

一些线程需要等待另外一些线程运行完毕才能运行,类似于发射信号一样

  1. from threading import Thread
  2.  
  3. from threading import Event
  4.  
  5. import time
  6. event = Event() #造了一个绿灯
  7. def light():
  8. print('等红灯')
  9. time.sleep(3)
  10. event.set() # 解除阻塞并且给 event发了一个信号
  11. print('绿灯亮了')
  12.  
  13. def car(i):
  14. print('%s灯红灯'%i)
  15. event.wait()
  16. print('%s绿灯了,加油门'%i)
  17.  
  18. if __name__ == '__main__':
  19. t = Thread(target=light)
  20. t.start()
  21.  
  22. p_list=[]
  23. for i in range(5):
  24. p = Thread(target=car,args=(i,))
  25. p.start()
  26.  
  27. # 等红灯
  28. # 0灯红灯
  29. # 1灯红灯
  30. # 2灯红灯
  31. # 3灯红灯
  32. # 4灯红灯
  33. # 绿灯亮了
  34. # 0绿灯了,加油门
  35. # 1绿灯了,加油门
  36. # 3绿灯了,加油门
  37. # 4绿灯了,加油门
  38. # 2绿灯了,加油门#

  

六.信号量(了解)

自定义的互斥锁如果是一个厕所,那么信号量就相当于公共厕所,门口挂着多个厕所的钥匙。抢和释放跟互斥锁一致

  1. 普通互斥锁, 独立卫生间 所有人只有一把锁
  2. 信号量 ,公共卫生间 有多少个坑 就有多少把锁
  3. """
  4. from threading import Thread
  5. from threading import Semaphore #信号量
  6. import time
  7. import random
  8. sm = Semaphore(5) #一个公共厕所造了5个坑 在厕所外放了5把锁
  9.  
  10. def task(name):
  11. sm.acquire() # 释放信号锁
  12.  
  13. print('%s正在蹲坑'%name)
  14. time.sleep(random.randint(1, 3))
  15. sm.release()
  16.  
  17. for i in range(20):
  18. t = Thread(target= task,args=('%s伞兵'%i,))
  19. t.start()

 

  1. 0伞兵正在蹲坑
  2. 1伞兵正在蹲坑
  3. 2伞兵正在蹲坑
  4. 3伞兵正在蹲坑
  5. 4伞兵正在蹲坑
  6. 此时5个人中 有一个人好了 同时释放了一把锁
  7. 5伞兵正在蹲坑
  8. 前面5个好了两个释放给 6,7
  9. 6伞兵正在蹲坑
  10. 7伞兵正在蹲坑
  11.  
  12. 8伞兵正在蹲坑
  13. 9伞兵正在蹲坑
  14. 10伞兵正在蹲坑
  15. 11伞兵正在蹲坑
  16.  
  17. 12伞兵正在蹲坑
  18. 13伞兵正在蹲坑
  19. 14伞兵正在蹲坑
  20. 15伞兵正在蹲坑
  21.  
  22. 16伞兵正在蹲坑
  23. 17伞兵正在蹲坑
  24. 18伞兵正在蹲坑
  25. 19伞兵正在蹲坑

  

  

七.线程queue

同一个进程下的线程数据都是共享的为什么还要用queue?queue本身自带锁的功能,能够保证数据的安全

  

  1. import queue
  2.  
  3. """
  4. 1.普通q
  5. 2.堆栈。先进后出q
  6. 3.优先级q
  7.  
  8. """
  9. q = queue.Queue(3)
  10. q.put(1)
  11. q.put(2)
  12.  
  13. q.put(3)
  14. print(q.get())
  15. print(q.get())
  16. print(q.get()) # 取值
    ——————》》》
    1
    2
    3
  17.  
  18. q = queue.LifoQueue(5)
  19. q.put(1)
  20. q.put(2)
  21. q.put(3)
  22. q.put(4)
  23. q.put(5)
  24.  
  25. print(q.get())
  26. print(q.get())
  27. print(q.get())
  28. print(q.get())
  29. print(q.get()) # 先进后出 和堆栈一样
    ——————》》》

5
4
3
2
1

  1. q = queue.PriorityQueue(3)
  2. q.put(100,"q")
  3. q.put(20,"t")
  4. q.put(-1,'s')
  5.  
  6. print(q.get())
  7. print(q.get())
  8. print(q.get()) # 优先级是按照数字从小到大排列的
    ————————》》》

-1
20
100

  

  

全局解释锁GIL的更多相关文章

  1. 并发、并行、同步、异步、全局解释锁GIL、同步锁Lock、死锁、递归锁、同步对象/条件、信号量、队列、生产者消费者、多进程模块、进程的调用、Process类、

    并发:是指系统具有处理多个任务/动作的能力. 并行:是指系统具有同时处理多个任务/动作的能力. 并行是并发的子集. 同步:当进程执行到一个IO(等待外部数据)的时候. 异步:当进程执行到一个IO不等到 ...

  2. python 全局解释锁GIL

    Python的全局解释器锁GIL用于保护python解释器,使得任意时刻,只有一个线程在解释器中运行.从而保证线程安全 在多线程环境中,Python 虚拟机按以下方式执行: 1. 设置GIL2. 切换 ...

  3. 什么是python的全局解释锁(GIL)

    GIL解决了Python中的什么问题? 为什么选取GIL作为解决方案? 对多线程Python程序的影响 为什么GIL还没有被删除? 为什么在Python 3 中GIL没有被移除? 如何处理Python ...

  4. GIL全局解释锁,死锁,信号量,event事件,线程queue,TCP服务端实现并发

    一.GIL全局解释锁 在Cpython解释器才有GIL的概念,不是python的特点 在Cpython解释器中,同一个进程下开启的多线程,同一时刻只能有一个线程执行,无法利用多核优势. 1.GIL介绍 ...

  5. 20191031:GIL全局解释锁

    20191031:GIL全局解释锁 总结关于GIL全局解释锁的个人理解 GIl全局解释锁,本身不是Python语言的特性,而是Python语言底层的c Python解释器的一个特性.在其他解释器中是没 ...

  6. ~~并发编程(十一):GIL全局解释锁~~

    进击のpython ***** 并发编程--GIL全局解释锁 这小节就是有些"大神"批判python语言不完美之处的开始 这一节我们要了解一下Cpython的GIL解释器锁的工作机 ...

  7. python 线程队列、线程池、全局解释器锁GIL

    一.线程队列 队列特性:取一个值少一个,只能取一次,没有值的时候会阻塞,队列满了,也会阻塞 queue队列 :使用import queue,用法与进程Queue一样 queue is especial ...

  8. 并发编程——全局解释器锁GIL

    1.全局解释器锁GIL GIL其实就是一把互斥锁(牺牲了效率但是保证了数据的安全). 线程是执行单位,但是不能直接运行,需要先拿到python解释器解释之后才能被cpu执行 同一时刻同一个进程内多个线 ...

  9. 你是否真的了解全局解析锁(GIL)

    关于我 一个有思想的程序猿,终身学习实践者,目前在一个创业团队任team lead,技术栈涉及Android.Python.Java和Go,这个也是我们团队的主要技术栈. Github:https:/ ...

随机推荐

  1. 开始玩矩阵了!先来一道入门题![SDOI2008]递归数列

    [SDOI2008]递归数列 题目描述 一个由自然数组成的数列按下式定义: 对于i <= k:ai = bi 对于i > k: ai = c1ai-1 + c2ai-2 + ... + c ...

  2. E. You Are Given Some Strings...

    E. You Are Given Some Strings... AC自动机 求一个串$t$中包含子串$s_{i}+s_{j}$的个数. 可以正反跑两遍AC自动机 正着跑,表示$s_{i}$结束,反正 ...

  3. Guava 已经学习的代码整理

    Guava 已经学习的代码整理 Guava 依赖: compile group: 'com.google.guava', name: 'guava', version: '18.0' 以下是我自己在开 ...

  4. 关于scroll,client,innear,avail,offset等的理解

    在写实例理解scrollWidth,clientWidth,innearWidth,availWidth及offsetWidth等的时候,意外的又发现了margin值合并的问题,在这里同时记录下 1. ...

  5. 【zabbix】zabbix 高可用架构的实现

    https://www.jianshu.com/p/249d47b089b4?utm_campaign=maleskine&utm_content=note&utm_medium=se ...

  6. 二进制安装MySQL5.6 MySQL5.7

    1:系统版本 [root@vhost1 ~]# cat /etc/redhat-release Red Hat Enterprise Linux Server release 6.5 (Santiag ...

  7. 术语-EDI:EDI

    ylbtech-术语-EDI:EDI 电子数据交换(Electronic data interchange,缩写EDI)是指按照同一规定的一套通用标准格式,将标准的经济信息,通过通信网络传输,在贸易伙 ...

  8. Linux_DNS服务器

    目录 目录 DNS DNS Server ServerSite Master DNS Server Forward Domain Reverse Resolution Slave DNS Server ...

  9. 转发与重定向(forward与redirect)

    顾名思义,转发是内部跳转:重定向是重新定向后跳转. 区别: 地址栏显示上: forward是服务器请求资源,服务器直接访问目标地址的URL,把那个URL的响应内容读取过来,然后把这些内容再发给浏览器. ...

  10. 双系统(win10+ubuntu)卸载Ubuntu系统

    之前装的双系统,Win10 和Ubuntu ,系统引导使用的是Ubuntu的Grup的引导, 直接删除Ubuntu会导致引导丢失,会很麻烦,win10直接会挂掉,后期恢复需要重建引导 安全删除思路,先 ...