1.全局解释器锁GIL

  • GIL其实就是一把互斥锁(牺牲了效率但是保证了数据的安全)。

  • 线程是执行单位,但是不能直接运行,需要先拿到python解释器解释之后才能被cpu执行

  • 同一时刻同一个进程内多个线程无法实现并行,但是可以实现并发

  • 为什么要有GIL是因为它内部的垃圾回收机制不是线程安全的

  • 垃圾回收机制也是一个任务,跟你的代码不是串行运行,如果是串行会明显有卡顿

  • 这个垃圾回收到底是开进程还是开线程?肯定是线程,线程肯定也是一段代码,所以想运行也必须要拿到python解释器

  • 假设能够并行,会出现什么情况?一个线程刚好要造一个a=1的绑定关系之前,这个垃圾线程来扫描,矛盾点就来了,谁成功都不对!

  • 也就意味着在Cpython解释器上有一把GIL全局解释器锁

  • 同一个进程下的多个线程不能实现并行但是能够实现并发,多个进程下的线程能够实现并行

1.python中的多线程到底有没有用?

单核情况下:四个任务

多核情况下:四个任务

计算密集型:一个任务算十秒,四个进程和四个线程,肯定是进程快

IO密集型:任务都是纯io情况下,线程开销比进程小,肯定是线程好

```python
# 计算密集型
from multiprocessing import Process
from threading import Thread
import os,time
def work():
res=0
for i in range(100000000):
res*=i if __name__ == '__main__':
l=[]
print(os.cpu_count()) # 本机为12核
start=time.time()
for i in range(12):
# p=Process(target=work) #耗时8s多
p=Thread(target=work) #耗时44s多
l.append(p)
p.start()
for p in l:
p.join()
stop=time.time()
print('run time is %s' %(stop-start)) # IO密集型
from multiprocessing import Process
from threading import Thread
import threading
import os,time
def work():
time.sleep(2) if __name__ == '__main__':
l=[]
print(os.cpu_count()) #本机为12核
start=time.time()
for i in range(400):
p=Process(target=work) #耗时12s多,大部分时间耗费在创建进程上
# 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))

2.GIL与自定义互斥锁

不同的数据需要加不同的锁才能保证数据的安全,GIL锁只是对线程加锁,对数据并没有加锁的效果

```python
from threading import Thread,Lock
import time mutex=Lock()
n=100
def task():
global n
with mutex:
temp=n
time.sleep(0.1)
n=temp-1 if __name__ == '__main__':
l=[]
for i in range(100):
t=Thread(target=task)
l.append(t)
t.start() for t in l:
t.join()
print(n)
# 对于修改不同的数据,需要加不同的锁进行处理

3.死锁与递归锁(了解)

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

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

from threading import Thread,Lock,RLock
import time # mutexA=Lock()
# mutexB=Lock()
mutexB=mutexA=RLock() class Mythead(Thread):
def run(self):
self.f1()
self.f2() def f1(self):
mutexA.acquire()
print('%s 抢到A锁' %self.name)
mutexB.acquire()
print('%s 抢到B锁' %self.name)
mutexB.release()
mutexA.release() def f2(self):
mutexB.acquire()
print('%s 抢到了B锁' %self.name)
time.sleep(2)
mutexA.acquire()
print('%s 抢到了A锁' %self.name)
mutexA.release()
mutexB.release() if __name__ == '__main__':
for i in range(100):
t=Mythead()
t.start()

4.信号量(了解)

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

from threading import Thread,Semaphore
import time
import random
sm = Semaphore(5) # 公共厕所里面有五个坑位,在厕所外面放了五把钥匙 def task(name):
sm.acquire()
print('%s正在蹲坑'%name)
# 模拟蹲坑耗时
time.sleep(random.randint(1,5))
sm.release() if __name__ == '__main__':
for i in range(20):
t = Thread(target=task,args=('伞兵%s号'%i,))
t.start()

5.Event事件

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

from threading import Thread,Event
import time
event = Event() # 造了一个红绿灯 def light():
print('红灯亮着的')
time.sleep(3)
print('绿灯亮了')
event.set() def car(name):
print('%s 车正在等红灯'%name)
event.wait()
print('%s 车加油门飙车走了'%name) if __name__ == '__main__':
t = Thread(target=light)
t.start() for i in range(10):
t = Thread(target=car,args=('%s'%i,))
t.start()

6.线程queue

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

# 我们现在的q只能在本地使用,后面我们会学基于网络的q
import queue queue.Queue() #先进先出
q=queue.Queue(3)
q.put(1)
q.put(2)
q.put(3)
print(q.get())
print(q.get())
print(q.get()) queue.LifoQueue() #后进先出->堆栈
q=queue.LifoQueue(3)
q.put(1)
q.put(2)
q.put(3)
print(q.get())
print(q.get())
print(q.get()) queue.PriorityQueue() #优先级
q=queue.PriorityQueue(3) #优先级,优先级用数字表示,数字越小优先级越高
q.put((10,'a'))
q.put((-1,'b'))
q.put((100,'c'))
print(q.get())
print(q.get())
print(q.get())

并发编程——全局解释器锁GIL的更多相关文章

  1. (并发编程)全局解释器锁(GIL)-----有了GIL不用给线程加锁了?

    一.全局解释器锁 (GIL)运行test.py的流程:a.将python解释器的代码从硬盘读入内存b.将test.py的代码从硬盘读入内存  (一个进程内装有两份代码---一份cpython解释器代码 ...

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

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

  3. 全局解释器锁GIL

    我们使用高并发,一次是创建1万个线程去修改一个数并打印结果看现象: from threading import Thread import os def func(args): global n n ...

  4. 全局解释器锁GIL & 线程锁

    1.GIL锁(Global Interpreter Lock) Python代码的执行由Python虚拟机(也叫解释器主循环)来控制.Python在设计之初就考虑到要在主循环中,同时只有一个线程在执行 ...

  5. python 什么是全局解释器锁GIL

    什么是全局解释器锁GIL Python代码的执行由Python 虚拟机(也叫解释器主循环,CPython版本)来控制,Python 在设计之初就考虑到要在解释器的主循环中,同时只有一个线程在执行,即在 ...

  6. 21.线程,全局解释器锁(GIL)

    import time from threading import Thread from multiprocessing import Process #计数的方式消耗系统资源 def two_hu ...

  7. python 多线程编程之使用进程和全局解释器锁GIL

    本文主要介绍如何在python中使用线程. 全局解释器锁: python代码的执行是由python虚拟机(又名解释器主循环)进行控制的.python中,主循环中同时只能有一个控制线程在执行,就像单核C ...

  8. Python核心技术与实战——十九|一起看看Python全局解释器锁GIL

    我们在前面的几节课里讲了Python的并发编程的特性,也了解了多线程编程.事实上,Python的多线程有一个非常重要的话题——GIL(Global Interpreter Lock).我们今天就来讲一 ...

  9. Python全局解释器锁 -- GIL

    首先强调背景: 1.GIL是什么?GIL的全称是Global Interpreter Lock(全局解释器锁),来源是python设计之初的考虑,为了数据安全所做的决定. 2.每个CPU在同一时间只能 ...

随机推荐

  1. Python笔记16-------类

    1.类的定义 (1)#括号中要加入父类,如果没有则默认为object,万类之源 class 类名(父类): '类的文档字符串' 类体代码 若类什么都不做,则类只作为命名空间,仅作为一个容器. (2)类 ...

  2. C++基础 (10) 第十天 C++中类型转换 异常 栈解旋 io操作

    1之前内容的回顾 C语言中的类型转换(int)a  强转可读性太差了 C++把()拆分成了四种转换方式 static_cast static_cast在编译器编译阶段就进行转换了 2.dynamic_ ...

  3. IOS开发:使用lipo合并armv7,i386,armv7s库文件

    假设多个版本的lib分别是 libxxx.armv7.a , libxxx.armv7s.a, libxxx.i386.a我们的目标是 把他们合并成超级通用版的libxxx.a  打开命令行 Term ...

  4. MySQL数据库中字段类型为tinyint,读取出来为true/false的问题

    由于MySQL中没有boolean类型,所以会用到tinyint类型来表示. 数据库一个表中有一个tinyint类型的字段,值为0或者1,如果取出来的话,0会变成false,1会变成true.

  5. linux采用scp命令拷贝文件到本地,拷贝本地文件到远程服务器

    // 假设远程服务器IP地址为 192.168.1.100 1.从服务器复制文件到本地: scp root@192.168.1.100:/data/test.txt /home/myfile/ roo ...

  6. C#使用 ComboBox 控件

    Combox控件是一个下拉选择的控件,再做上位机的时候会经常用到,这里记录一下我是怎么用. 1.拉出一个combox控件 2.控件属性选为不可编辑,可编辑的话,你选择下拉框的内容后可以改下拉框里的内容 ...

  7. ajax提交数据遇到400异常,原因及解决方案

    开发中遇到的问题, ajax的URL写的正确但是确无法正常跳转, 开发者模式下显示请求400异常. 前后台代码如下 ------------------------------------------ ...

  8. poj 2377 最大生成树

    #include<stdio.h> #include<stdlib.h> #define N 1100 struct node { int u,v,w; }bian[11000 ...

  9. yiii 数据库备份导出

    应用场景 数据对于网站来说 是非常重要的 一般 cms 后台 都有 数据备份功能.使用Yii 的第三方拓展 可以快速开发. spanjeta/yii2-backup spanjeta/yii2-bac ...

  10. ORACLE-游标数

    .查看系统配置游标数 select value from v$parameter where name = 'open_cursors'; .查看游标使用情况 select o.sid, osuser ...