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多线程锁
[Python之旅]第六篇(四):Python多线程锁 python lock 多线程 多线程使用方法 多线程锁 摘要: 在多线程程序执行过程中,为什么需要给一些线程加锁以及如何加锁,下面就来 ...
- python基础之多线程锁机制
GIL(全局解释器锁) GIL并不是Python的特性,它是在实现Python解析器(CPython)时所引入的一个概念,是为了实现不同线程对共享资源访问的互斥,才引入了GIL 在Cpython解释器 ...
- Python开发基础-Day30多线程锁机制
GIL(全局解释器锁) GIL并不是Python的特性,它是在实现Python解析器(CPython)时所引入的一个概念,是为了实现不同线程对共享资源访问的互斥,才引入了GIL 在Cpython解释器 ...
- [java多线程] - 锁机制&同步代码块&信号量
在美眉图片下载demo中,我们可以看到多个线程在公用一些变量,这个时候难免会发生冲突.冲突并不可怕,可怕的是当多线程的情况下,你没法控制冲突.按照我的理解在java中实现同步的方式分为三种,分别是:同 ...
- python多线程同步机制Semaphore
#!/usr/bin/env python # -*- coding: utf-8 -*- """ Python 线程同步机制:Semaphore "" ...
- Python高阶之多线程锁机制
'''1.多进程的优势:为了同步完成多项任务,通过提高资源使用效率来提高系统的效率.2.查看线程数:threading.enumerate()函数便可以看到当前线程的数量.3.查看当前线程的名字:th ...
- python多线程同步机制condition
#!/usr/bin/env python# -*- coding: utf-8 -*- import threadingimport time def customer(cond): t = thr ...
- python多线程同步机制Lock
#!/usr/bin/env python# -*- coding: utf-8 -*- import threadingimport time value = 0lock = threading.L ...
- python多线程锁lock/Rlock/BoundedSemaphore/Condition/Event
import time import threading lock = threading.RLock() n = 10 def task(arg): # 加锁,此区域的代码同一时刻只能有一个线程执行 ...
随机推荐
- HTML5 缓存: cache manifest
---恢复内容开始--- 1:MIME TYPE:text/cache-manifest 服务器配置MIME类型2:需要由你创建的:NAME.manifest 创建manifest文件3:给 < ...
- HTML 转义字符对应表
<%@ tag language="java" pageEncoding="UTF-8" %> <%@ attribute name=&quo ...
- PDF文件怎么修改,PDF文件编辑方法
PDF文件是一种独特的文件,在日常办公中已经成为我们使用最广泛的电子文档格式.在使用PDF文件中会遇到PDF文件有错区的时候,再从新制作一个PDF文件会比较麻烦,只能通过工具来对PDF文件进行修改,这 ...
- CSS3媒体查询的部分重要属性
width:视口宽度 height:视口高度 device-width:渲染表面的宽度,就是设备屏幕的宽度 device-height:渲染表面的高度,就是设备屏幕的高度 orientation:检查 ...
- getComputedStyle()用法详解
那如果元素即没有在style属性中设置宽高,也没有在样式表中设置宽高,还能用getComputedStyle或currentStyle获取吗?答案是getComputedStyle可以,current ...
- python发送邮件(在邮件中显示HTMLTestRunner生成的报告)
import smtplib from email.mime.text import MIMEText from email.mime.multipart import MIMEMultipart f ...
- python Com接口测试
import comtypes.client as cc import comtypes tlb_id = comtypes.GUID("{D85C6069-D628-4276-93C3-9 ...
- win(64位)环境下oracle11g的安装方法
将压缩文件解压到一个目录中,该目录结构如下: 安装步骤(摘自网络): 1.进入数据库解压目录,双击其中的“setup.exe”文件,稍等片刻出现如下“配置安全更新“界面,取消“我希望通过My Orac ...
- (原创)C# 压缩解压那些事儿
吐槽: 搜狗推广API的报告服务太坑爹了!!! 搜狗推广API的报告服务太坑爹了!!! 搜狗推广API的报告服务太坑爹了!!! 搜狗的太垃圾了,获取下来的压缩包使用正常方式无法解压!!没有专门的API ...
- 计算1至n中数字X出现的次数【math】
转自: nailperry 一.1的数目 编程之美上给出的规律: 1. 如果第i位(自右至左,从1开始标号)上的数字为0,则第i位可能出现1的次数由更高位决定(若没有高位,视高位为0),等于更高位数字 ...