python基础之多线程锁机制
GIL(全局解释器锁)
GIL并不是Python的特性,它是在实现Python解析器(CPython)时所引入的一个概念,是为了实现不同线程对共享资源访问的互斥,才引入了GIL
在Cpython解释器中,同一个进程下开启的多线程,同一时刻只能有一个线程执行,无法利用多核优势

python对于计算密集型的任务开多线程的效率甚至不如串行(没有大量切换),但是,对于IO密集型的任务效率还是有显著提升的。
GIL原理图

计算密集型:结果肯定是100,因为每一次start结果就已经出来了,所以第二个线程肯定是通过调用第一个线程的count值进行计算的
1 def sub():
2 global count
3
4 '''线程的公共数据 下'''
5 temp=count
6 count=temp+1
7 '''线程的公共数据 上'''
8
9 time.sleep(2)
10 count=0
11
12 l=[]
13 for i in range(100):
14 t=threading.Thread(target=sub,args=())
15 t.start() #每一次线程激活,申请一次gillock
16 l.append(t)
17 for t in l:
18 t.join()
19 print(count)
io密集型:当第一个线程开始start的时候,由于sleep了0.001秒,这0.001秒对于人而言很短,但是对于cpu而言,这0.001秒已经做了很多的事情了,在这里cpu做的事情就是或许已经start了100个线程,所以导致大多数的线程调用的count值还是0,即temp=0,只有少数的线程完成了count=temp+1的操作,所以输出的count结果不确定,可能是7、8、9,也可能是10几。
1 def sub():
2 global count
3
4 '''线程的公共数据 下'''
5 temp=count
6 time.sleep(0.001) #大量的io操作
7 count=temp+1
8 '''线程的公共数据 上'''
9
10 time.sleep(2)
11 count=0
12
13 l=[]
14 for i in range(100):
15 t=threading.Thread(target=sub,args=())
16 t.start()
17 l.append(t)
18 for t in l:
19 t.join()
20 print(count)
注意以下的锁都是多线程提供的锁机制,与python解释器引入的gil概念无关
互斥锁(同步锁)
互斥锁是用来解决上述的io密集型场景产生的计算错误,即目的是为了保护共享的数据,同一时间只能有一个线程来修改共享的数据。
1 def sub():
2 global count
3 lock.acquire() #上锁,第一个线程如果申请到锁,会在执行公共数据的过程中持续阻塞后续线程
4 #即后续第二个或其他线程依次来了发现已经被上锁,只能等待第一个线程释放锁
5 #当第一个线程将锁释放,后续的线程会进行争抢
6
7 '''线程的公共数据 下'''
8 temp=count
9 time.sleep(0.001)
10 count=temp+1
11 '''线程的公共数据 上'''
12
13 lock.release() #释放锁
14 time.sleep(2)
15 count=0
16
17 l=[]
18 lock=threading.Lock() #将锁内的代码串行化
19 for i in range(100):
20 t=threading.Thread(target=sub,args=())
21 t.start()
22 l.append(t)
23 for t in l:
24 t.join()
25 print(count)
死锁
保护不同的数据就应该加不同的锁。
所以当有多个互斥锁存在的时候,可能会导致死锁,死锁原理如下:
1 import threading
2 import time
3 def foo():
4 lockA.acquire()
5 print('func foo ClockA lock')
6 lockB.acquire()
7 print('func foo ClockB lock')
8 lockB.release()
9 lockA.release()
10
11 def bar():
12
13 lockB.acquire()
14 print('func bar ClockB lock')
15 time.sleep(2) # 模拟io或者其他操作,第一个线程执行到这,在这个时候,lockA会被第二个进程占用
16 # 所以第一个进程无法进行后续操作,只能等待lockA锁的释放
17 lockA.acquire()
18 print('func bar ClockA lock')
19 lockB.release()
20 lockA.release()
21
22 def run():
23 foo()
24 bar()
25
26 lockA=threading.Lock()
27 lockB=threading.Lock()
28 for i in range(10):
29 t=threading.Thread(target=run,args=())
30 t.start()
31
32 输出结果:只有四行,因为产生了死锁阻断了
33 func foo ClockA lock
34 func foo ClockB lock
35 func bar ClockB lock
36 func foo ClockA lock
递归锁(重要)
解决死锁
1 import threading
2 import time
3 def foo():
4 rlock.acquire()
5 print('func foo ClockA lock')
6 rlock.acquire()
7 print('func foo ClockB lock')
8 rlock.release()
9 rlock.release()
10
11 def bar():
12 rlock.acquire()
13 print('func bar ClockB lock')
14 time.sleep(2)
15 rlock.acquire()
16 print('func bar ClockA lock')
17 rlock.release()
18 rlock.release()
19
20
21 def run():
22 foo()
23 bar()
24
25 rlock=threading.RLock() #RLock本身有一个计数器,如果碰到acquire,那么计数器+1
26 #如果计数器大于0,那么其他线程无法查收,如果碰到release,计数器-1
27
28 for i in range(10):
29 t=threading.Thread(target=run,args=())
30 t.start()
Semaphore(信号量)
实际上也是一种锁,该锁用于限制线程的并发量
以下代码在sleep两秒后会打印出100个ok
1 import threading
2 import time
3 def foo():
4 time.sleep(2)
5 print('ok')
6
7 for i in range(100):
8 t=threading.Thread(target=foo,args=())
9 t.start()
每2秒打印5次ok
1 import threading
2 import time
3 sem=threading.Semaphore(5)
4 def foo():
5 sem.acquire()
6 time.sleep(2)
7 print('ok')
8 sem.release()
9
10 for i in range(100):
11 t=threading.Thread(target=foo,args=())
12 t.start()
python基础之多线程锁机制的更多相关文章
- Python开发基础-Day30多线程锁机制
GIL(全局解释器锁) GIL并不是Python的特性,它是在实现Python解析器(CPython)时所引入的一个概念,是为了实现不同线程对共享资源访问的互斥,才引入了GIL 在Cpython解释器 ...
- python基础-12 多线程queue 线程交互event 线程锁 自定义线程池 进程 进程锁 进程池 进程交互数据资源共享
Python中的进程与线程 学习知识,我们不但要知其然,还是知其所以然.你做到了你就比别人NB. 我们先了解一下什么是进程和线程. 进程与线程的历史 我们都知道计算机是由硬件和软件组成的.硬件中的CP ...
- python 多线程锁机制
GIL(全局解释器锁) GIL并不是Python的特性,它是在实现Python解析器(CPython)时所引入的一个概念,是为了实现不同线程对共享资源访问的互斥,才引入了GIL 在Cpython解释器 ...
- python基础之多线程与多进程(二)
上课笔记整理: 守护线程的作用,起到监听的作用 一个函数连接数据库 一个做守护线程,监听日志 两个线程同时取一个数据 线程---->线程安全---->线程同时进行操作数据. IO操作--- ...
- [java多线程] - 锁机制&同步代码块&信号量
在美眉图片下载demo中,我们可以看到多个线程在公用一些变量,这个时候难免会发生冲突.冲突并不可怕,可怕的是当多线程的情况下,你没法控制冲突.按照我的理解在java中实现同步的方式分为三种,分别是:同 ...
- Python高阶之多线程锁机制
'''1.多进程的优势:为了同步完成多项任务,通过提高资源使用效率来提高系统的效率.2.查看线程数:threading.enumerate()函数便可以看到当前线程的数量.3.查看当前线程的名字:th ...
- python基础之多线程与多进程(一)
并发编程? 1.为什么要有操作系统? 操作系统,位于底层硬件与应用软件之间 工作方式:向下管理硬件,向上提供接口 2.多道技术? 不断切换程序. 操作系统进程切换: 1.出现IO操作 2.固定时间 进 ...
- Python学习 :多线程 --- 锁
多线程 什么是锁? - 锁通常被用来实现对共享资源的同步访问. - 为每一个共享资源创建一个Lock对象,当你需要访问该资源时,调用acquire方法来获取锁对象(如果其它线程已经获得了该锁,则当前线 ...
- 【java基础】Java锁机制
在读很多并发文章中,会提及各种各样锁如公平锁,乐观锁等等,这篇文章介绍各种锁的分类.介绍的内容如下: 公平锁/非公平锁 可重入锁 独享锁/共享锁(广义) 互斥锁/读写锁(独享锁/共享锁的实现) 乐观锁 ...
随机推荐
- Apache nutch1.5 & Apache solr3.6
第1章引言 1.1nutch和solr Nutch 是一个开源的.Java 实现的搜索引擎.它提供了我们运行自己的搜索引擎所需的全部工具. Solr 拥有像 web-services API 的独立的 ...
- 基于Cocos2d-x学习OpenGL ES 2.0系列——OpenGL ES渲染之LayerColor(8)
在前面文章中讲述了Cocos2d-x引擎OpenGL渲染准备Shader方面,本文主要讲解使用LayerColor来讲述OpenGL的渲染过程. 1.LayerColor对象创建 添加LayerCol ...
- iOS @synthesize var = _var 变量前置下划线解释
本文转载至 http://blog.csdn.net/ztp800201/article/details/9231617 前置下划线是一种为了帮助区分实例变量和访问方法的约定.对于编译器来说它只是一 ...
- Android 监听按钮的点击事件
onClick事件1.Button和ImageButton都拥有一个onClick事件 通过自身的.setOnClickListener(OnClickListener)方法添加点击事件2.所有的控件 ...
- 打造不死的asp木马
作者:黑色记忆本文已发表于<黑客X档案>杂志第十期 版权归<黑客X档案>所有 转载请注明版权 想不到,前几天我才发现,我千辛万苦收集的asp木马,居然没有几个不被Kill的.常 ...
- shell脚本分析nginx日志
shell脚本分析nginx日志: name=`awk -F ',' '{print $13":"$32}' $file | awk -F ':' '{print $4}'`ech ...
- MySQL监控、性能分析——工具篇(转载)
MySQL越来越被更多企业接受,随着企业发展,MySQL存储数据日益膨胀,MySQL的性能分析.监控预警.容量扩展议题越来越多.“工欲善其事,必先利其器”,那么我们如何在进行MySQL性能分析.监控预 ...
- yii 表单如何写,action指向哪里?
文本框:textInput(); 密码框:passwordInput(); 单选框:radio(),radioList(); 复选框:checkbox(),checkboxList(); 下拉框:dr ...
- Feature extraction using convolution
http://ufldl.stanford.edu/wiki/index.php/Feature_extraction_using_convolution http://ufldl.stanford. ...
- 双态运维联盟(BOA)正式成立
3月1日,由联想.新华三.华为等12家IT企业在北京正式达成协议,联合发起成立“双态运维联盟”.中国电子工业标准技术协会.信息技术服务分会数据中心运营管理工作组(DCMG)组长肖建一先生出席了会议. ...