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锁机制
在读很多并发文章中,会提及各种各样锁如公平锁,乐观锁等等,这篇文章介绍各种锁的分类.介绍的内容如下: 公平锁/非公平锁 可重入锁 独享锁/共享锁(广义) 互斥锁/读写锁(独享锁/共享锁的实现) 乐观锁 ...
随机推荐
- timerWithTimeInterval 方法详用
1.初始化 + (NSTimer *)timerWithTimeInterval:(NSTimeInterval)ti target:(id)aTarget selector:(SEL)aSelect ...
- VS2013快捷键
这个好用,先放这两个 组合键“Ctrl+Enter”:在当前行的上面插入一个空行: 组合键“Ctrl+Shift+Enter”:在当前行的下面插入一个空行.
- 腾讯正式开源高性能超轻量级 PHP 框架 Biny
概况 Biny是一款高性能的超轻量级PHP框架 遵循 MVC 模式,用于快速开发现代 Web 应用程序 Biny代码简洁优雅,对应用层,数据层,模板渲染层的封装简单易懂,能够快速上手使用 高性能,框架 ...
- 【WebService】快速构建WebService示例
package com.slp.webservice; import javax.jws.WebService; /** * Created by sanglp on 2017/2/25. * 接口 ...
- Python的反序列化漏洞
最近准备研究一下反序列化漏洞,但是Java代码看不懂,所以先找一个python的看起,毕竟这种漏洞在python.php中一样存在,等研究明白了基本原理后去看java的反序列化漏洞. python反序 ...
- 【BZOJ1458】士兵占领 最小流
[BZOJ1458]士兵占领 Description 有一个M * N的棋盘,有的格子是障碍.现在你要选择一些格子来放置一些士兵,一个格子里最多可以放置一个士兵,障碍格里不能放置士兵.我们称这些士兵占 ...
- opencv学习笔记——图像缩放函数resize
opencv提供了一种图像缩放函数 功能:实现对输入图像缩放到指定大小 函数原型: void cv::resize ( InputArray src, OutputArray dst, Size ds ...
- Python实现进程同步和通信
转自:https://blog.csdn.net/u014556057/article/details/66974452
- SpringCloud 进阶之Zuul(路由网关)
1. Zuul(路由网关) Zuul 包含了对请求的路由和过滤两个最主要的功能; 路由功能:负责将外部请求转发到具体的微服务实例上,是实现外部访问统一入口的基础; 过滤功能:负责对请求的处理过程进行干 ...
- Git学习-->如何通过Shell脚本自动定时将Gitlab备份文件复制到远程服务器?
一.背景 在我之前的博客 git学习--> Gitlab如何进行备份恢复与迁移? (地址:http://blog.csdn.net/ouyang_peng/article/details/770 ...