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.)
'''
结论:在Cpython解释器中,同一个进程下开启的多线程,同一时刻只能有一个线程执行,无法利用多核优势
首先需要明确的一点是GIL并不是Python的特性,它是在实现Python解析器(CPython)时所引入的一个概念。就好比C++是一套语言(语法)标准,但是可以用不同的编译器来编译成
可执行代码。有名的编译器例如GCC,INTEL C++,Visual C++等。Python也一样,同样一段代码可以通过CPython,PyPy,Psyco等不同的Python执行环境来执行。像其中的
JPython就没有GIL。然而因为CPython是大部分环境下默认的Python执行环境。所以在很多人的概念里CPython就是Python,也就想当然的把GIL归结为Python语言的缺陷。所以这
里要先明确一点:GIL并不是Python的特性,Python完全可以不依赖于GIL
垃圾回收机制
x = 10
x = 2 # x重新赋值为2 , Cpython 解释器会开启一个垃圾回收线程,把 10 给回收掉
y = 10 #如果多线程并发或并行,就有可能其他线程会要用到这个地址,一个要回收,一个要用,就会产生矛盾.这显然是不行的
有了GIL后:
垃圾回收线程执行的时候,其他线程不能动(垃圾回收线程从头到尾执行完毕,其他线程才能运行)
其他线程执行的时候,垃圾回收线程不能动
垃圾回收:定义一个变量,当这个变量以后不再被引用,这个变量就要回收掉,解释器开了线程帮程序员干了这活(其他语言需要程序员自己回收),把程序员解放出来了.
python的多线程特点:
基于cpython写的,同一时刻只能有一个线程执行
cpu是干计算的,不是io ,所以io密集型的程序用不了多核也影响不大,基本忽略不计
==================================
多个进程,每个进程只有一个线程,有没有gil无所谓(gil锁作用与多线程)
所以,多个进程可以用多核(Cpython)
GIl本质是互斥锁
既然是互斥锁,所有互斥锁的本质都一样,都是将并发运行变成串行,以此来控制同一时间内共享数据只能被一个任务所修改,进而保证数据安全。
可以肯定的一点是:保护不同的数据的安全,就应该加不同的锁。
GIL 和 Lock
GIL锁,保护的是解释器级别的数据
Lock锁,保护的是用户自己的数据
应用:
多线程用于IO密集型,如socket,爬虫,web
多进程用于计算密集型,如金融分析
=========================
3个线程都去抢GIL锁,假如线程1 抢到了,那么线程1 就会把代码传给解释器编译执行,然后拿到Lock,遇到sleep,睡0.1秒,操作系统强制线程1把GIL锁释放,线程1 睡的时候,线程1 就没
资格抢gil,所以剩下的是线程2和线程3它们俩抢,当一个抢到GIL锁后,就会把代码传给解释器执行,当运行到Lock时,下面的代码已经被线程1锁住,然后系统就会强制这个线程释放GIL
锁,.直到线程1 睡醒了 ,才有资格抢GIL,当线程1再次抢到GIL后,线程1就会从当前位置继续往下执行.
小节:
1.每一个Cpython进程内都有一个GIL
2.GIL导致同一个进程内的多个线程同一时间只能有一个运行
3.之所以有GIL,是因为Cpython的内存管理不是线程安全的
4.对于计算密集型用多进程,IO密集型用多线程
死锁和递归锁
import time
from threading import Thread, Lock class Myth(Thread):
def run(self):
self.f1()
self.f2() def f1(self):
mutexA.acquire()
print('%s拿到A锁' % self.name) #线程对象自带name属性
time.sleep(0.2)
mutexB.acquire()
print('%s拿到B锁' % self.name)
mutexB.release()
print('%s释放B锁' % self.name)
mutexA.release()
print('%s释放A锁' % self.name) def f2(self):
mutexB.acquire()
print('%s拿到B锁' % self.name)
time.sleep(0.2)
mutexA.acquire()
print('%s拿到A锁' % self.name)
mutexA.release()
print('%s释放A锁' % self.name)
mutexB.release()
print('%s释放B锁' % self.name) if __name__ == '__main__':
mutexA = Lock()
mutexB = Lock()
for i in range(100):
t = Myth()
t.start() Thread-1拿到A锁
Thread-1拿到B锁
Thread-1释放B锁
Thread-1释放A锁 释放掉之后再抢
Thread-1拿到B锁
Thread-2拿到A锁 一人拿一个,需要的都在对方手里,结果都拿不到对方的锁
..
然后程序卡死了
定时器
定时器,指定n秒后执行某操作
from threading import Timer def func(name):
print('%s is done' % name) t = Timer(1, func, args=('kitty',))
t.start()
##
kitty is done #一秒之后执行func
GIL锁、死锁、递归锁、定时器的更多相关文章
- python 线程(创建2种方式,锁,死锁,递归锁,GIL锁,守护进程)
###############总结############ 线程创建的2种方式(重点) 进程:资源分配单位 线程:cpu执行单位(实体) 线程的创建和销毁的开销特别小 线程之间资源共享,是同一个 ...
- day33 线程的创建 验证线程之间共享数据 守护线程 线程进程效率对比 锁 死锁 递归锁
今日内容: 1.线程理论 2.锁: 牺牲了效率,保证了数据的安全(重点) 3.守护线程 4.GIL锁:(重点) 5.计算密集型和IO密集型 6.信号量,事件(了解) 7.补充. 子进程中不能input ...
- 并发编程8 线程的创建&验证线程之间数据共享&守护线程&线程进程效率对比&锁(死锁/递归锁)
1.线程理论以及线程的两种创建方法 2.线程之间是数据共享的与join方法 3.多线程和多进程的效率对比 4.数据共享的补充线程开启太快 5.线程锁 互斥锁 同步锁 6.死锁现象和递归锁 7.守护线程 ...
- python并发编程-多线程实现服务端并发-GIL全局解释器锁-验证python多线程是否有用-死锁-递归锁-信号量-Event事件-线程结合队列-03
目录 结合多线程实现服务端并发(不用socketserver模块) 服务端代码 客户端代码 CIL全局解释器锁****** 可能被问到的两个判断 与普通互斥锁的区别 验证python的多线程是否有用需 ...
- 并发编程---死锁||递归锁---信号量---Event事件---定时器
死锁 互斥锁:Lock(),互斥锁只能acquire一次 递归锁: RLock(),可以连续acquire多次,每acquire一次计数器+1,只有计数为0时,才能被抢到acquire # 死锁 f ...
- ReactiveSwift源码解析(十一) Atomic的代码实现以及其中的Defer延迟、Posix互斥锁、递归锁
本篇博客我们来聊一下ReactiveSwift中的原子性操作,在此内容上我们简单的聊一下Posix互斥锁以及递归锁的概念以及使用场景.然后再聊一下Atomic的代码实现.Atomic主要负责多线程下的 ...
- day 7-6 GIL,死锁,递归锁与信号量,Event,queue,
摘要: 1.死锁与递归锁 2.信号量 3.Event 4.Timer 5.GIL 6.Queue 7.什么时候该用多线程和多进程 一. 死锁与递归锁 所谓死锁: 是指两个或两个以上的进程或线程在执行过 ...
- python-GIL、死锁递归锁及线程补充
一.GIL介绍 GIL全称 Global Interpreter Lock ,中文解释为全局解释器锁.它并不是Python的特性,而是在实现python的主流Cpython解释器时所引入的一个概念,G ...
- 线程、进程、daemon、GIL锁、线程锁、递归锁、信号量、计时器、事件、队列、多进程
# 本文代码基于Python3 什么是进程? 程序并不能单独运行,只有将程序装载到内存中,系统为它分配资源才能运行,而这种执行的程序就称之为进程.程序和进程的区别就在于:程序是指令的集合,它是进程运行 ...
- python并发编程之多线程2------------死锁与递归锁,信号量等
一.死锁现象与递归锁 进程也是有死锁的 所谓死锁: 是指两个或两个以上的进程或线程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用, 它们都将无法推进下去.此时称系统处于死锁状态或系统 ...
随机推荐
- linux——nmap端口扫描命令
先安装 nmap :apt-get install nmap 端口扫描命令nmap -sS 172.16.55.100nmap -Pn 172.16.55.100第一组渗透测试指令,用于情报收集. 要 ...
- JS添加验证页面中script标签中是否存在jquery文件
window.onload = function() { var al = document.getElementsByTagName("script"); var new_ele ...
- 单机简单搭建一个kafka集群(没有进行内核参数和JVM的调优)
1.JDK安装 在我的部署单节点kafka的博客里有相关的方法.(https://www.cnblogs.com/ToBeExpert/p/9789486.html )zookeeper和kafka的 ...
- (56)zabbix Screens视图配置
screen翻译成中文为“屏幕”,在超市.单位等等地方都比较常见到监控视频,视频上有多块小视频,实际上zabbix screen和这个功能类似.你可以设置多个screen,每个screen可以显示特定 ...
- GIMP暗黑诱惑,部分彩色效果制作
在一些图形处理中经常会用到高逼格的部分彩色,其他部分黑白的效果,今天我就简单记录一下如何操作. 1.选区,先选择要突出的选区,可以用多种方法,钢笔,套绳,小剪刀等等: 2.把选择的区域稍稍调整亮一点: ...
- python-小数据池,再谈编码,is和 == 的区别
一 . 小数据池 # 小数据池针对的是: int, str, bool 在py文件中几乎所有的字符串都会缓存. # id() 查看变量的内存地址 s = 'attila' print(id(s)) 二 ...
- 数据结构( Pyhon 语言描述 ) — —第9章:列表
概念 列表是一个线性的集合,允许用户在任意位置插入.删除.访问和替换元素 使用列表 基于索引的操作 基本操作 数组与列表的区别 数组是一种具体的数据结构,拥有基于单个的物理内存块的一种特定的,不变的实 ...
- cocos2d心得关于精灵帧缓存
在cocos2d中,精灵帧缓存CCSpriteFrameCache是用来存储精灵帧的.它没有特别的属性,只存储了一些用来管理CCSpriteFrame的方法. 以一个例子来说明,一般在又纹理图集的程序 ...
- c++ heap学习
heap并不属于STL容器组件,它分为 max heap 和min heap,在缺省情况下,max-heap是优先队列(priority queue)的底层实现机制. 而这个实现机制中的max-hea ...
- SGU 149 树形DP Computer Network
这道题搜了一晚上的题解,外加自己想了半个早上,终于想得很透彻了.于是打算好好写一写这题题解,而且这种做法比网上大多数题解要简单而且代码也比较简洁. 首先要把题读懂,把输入读懂,这实际上是一颗有向树.第 ...