1.锁的形象解释

有一个奇葩的房东,他家里有两个房间想要出租。这个房东很抠门,家里有两个房间,但却只有一把锁,不想另外花钱是去买另一把锁,也不让租客自己花钱加锁。这样租客只有先租到的那个人才能分配到锁。X先生,率先租到了房子,并且拿到了锁。而后来者Y先生,由于锁已经已经被X取走了,自己拿不到锁,也不能自己加锁,Y就不愿意了,也就不租了。换作其他人也一样,没有人会租第二个房间,直到X先生退租,把锁还给房东,可以让其他房客来取,第二间房间才能租出去。
换句话说,就是房东同时只能出租一个房间,一但有人租了一个房间,拿走了唯一的锁,就没有人再在租另一间房了。
回到线程中来,假设有两个线程A和B,A和B里的程序都加了同一个锁对象,当线程A率先执行到lock.acquire()(拿到全局唯一的锁后),线程B只能等到线程A释放锁lock.release()后(归还锁)才能运行lock.acquire()(拿到全局唯一的锁)并执行后面的代码。

2.如何使用"锁"?

import threading# 生成锁对象,全局唯一
lock = threading.Lock()
# 获取锁,没有获得到锁的程序会陷入阻塞,直到程序重新获取到锁才能往下执行
lock.acquire()
# 释放锁,此时,其他程序可以使用锁了
lock.release()

注意:lock.acquire()与lock.release()必须成对使用,否则会造成死锁!!!为了有时候忘记,推荐使用上下文管理器来加锁,类似于tensorflow中的with tf.Session() as sess:

lock = threading.Lock()
with lock:# 写自己的业务逻辑代码pass

上面的with语句会在代码执行前自动获取锁,在执行结束后自动释放锁

3.可重入锁(RLock)

有时候在同一个线程中,我们可能会多次请求同一资源(就是,获取同一个锁的钥匙),俗称锁嵌套。如果还是按照常规的做法,会造成死锁的。比如,下面这段代码,你可以试着运行一下,会发现并没有输出结果。

import threadingdef main():n = 0lock = threading.Lock()with lock:for i in range(10):n += 1with lock:print(n)t1 = threading.Thread(target=main)
t1.start()

原因:在第二次获取锁时,发现锁已经被同一线程的人拿走了,自己也就理所当然拿不到锁了,所以程序卡住了。
解决方法:threading模块除了提供Lock锁之外,还提供了一种可重入锁RLock,专门来处理这个问题。

import threadingdef main():n = 0lock = threading.RLock()    # 生成可重入锁对象with lock:for i in range(10):n += 1with lock:print(n)t1 = threading.Thread(target=main)
t1.start()

注意: 可重入锁只能用在同一线程里,放松对锁钥匙的获取,其他与普通的Lock没啥不同。

4.防止死锁的加锁机制

死锁出现的情况:1.同一线程中,嵌套获取同一把锁,造成死锁;2.多个线程,不按顺序同时获取多个锁,造成死锁。例如:线程1:嵌套获取A,B两个锁;线程2:嵌套获取B,A两个锁。 由于两个线程是交替执行的,是有机会遇到线程1获取到锁A,而未获取到锁B,在同一时刻,线程2获取到锁B,而未获取到锁A。由于锁B已经被线程2获取了,所以线程1就卡在了获取锁B处,由于是嵌套锁,线程1未获取并释放B,是不能释放锁A的,这是导致线程2也获取不到锁A,也卡住了。两个线程,各执一锁,各不让步。造成死锁。
解决方法: 只要两个(或多个)线程获取嵌套锁时,按照固定顺序就能保证程序不会进入死锁状态。那么问题就转化成如何保证这些锁是按顺序的?(人工自觉,人工识别( 写一个辅助函数来对锁进行排序))

import threading
from contextlib import contextmanager# 人工识别方法来排序
# Thread-local state to stored information on locks already acquired
_local = threading.local()@contextmanager
def acquire(*locks):# Sort locks by object identifierlocks = sorted(locks, key=lambda x: id(x))# Make sure lock order of previously acquired locks is not violatedacquired = getattr(_local,'acquired',[])if acquired and max(id(lock) for lock in acquired) >= id(locks[0]):raise RuntimeError('Lock Order Violation')# Acquire all of the locksacquired.extend(locks)_local.acquired = acquiredtry:for lock in locks:lock.acquire()yieldfinally:# Release locks in reverse order of acquisitionfor lock in reversed(locks):lock.release()del acquired[-len(locks):]
# 使用上面定义的人工识别方法
import threading
x_lock = threading.Lock()
y_lock = threading.Lock()def thread_1():while True:with acquire(x_lock):with acquire(y_lock):print('Thread-1')def thread_2():while True:with acquire(y_lock):with acquire(x_lock):print('Thread-2')t1 = threading.Thread(target=thread_1)
t1.daemon = True
t1.start()t2 = threading.Thread(target=thread_2)
t2.daemon = True
t2.start()

分析:表面上thread_1的先获取锁x,再获取锁y,而thread_2是先获取锁y,再获取x。 但是实际上,acquire函数,已经对x,y两个锁进行了排序。所以thread_1,hread_2都是以同一顺序来获取锁的,是不会造成死锁的。

5.GIL(全局锁)

多进程是真正的并行,而多线程是伪并行,实际上他只是交替执行。由于GIL导致多线程实际上是伪并行的。因为任何Python线程执行前,必须先获得GIL锁。然后,每执行100条字节码,解释器就自动释放GIL锁,让别的线程有机会执行。这个GIL全局锁实际上把所有线程的执行代码都给上了锁。所以,多线程在Python中只能交替执行,即使100个线程跑在100核CPU上,也只能用到1个核。
注意:GIL并不是Python的特性,它是在实现Python解析器(CPython)时所引入的一个概念。而Python解释器,并不是只有CPython。除它之外,还有PyPy,Psyco,JPython,IronPython等。在绝大多数情况下,我们通常都认为 Python == CPython,所以也就默许了Python具有GIL锁这个事。
解决方法: 1.使用多进程代替多线程;2.更换Python解释器,不使用CPython

6.参考博客链接

python编程时光

python3线程中的锁机制相关推荐

  1. python锁机制_Python并发编程之谈谈线程中的“锁机制”(三)

    大家好,并发编程 进入第三篇. 今天我们来讲讲,线程里的锁机制. 本文目录 何为Lock( 锁 )?如何使用Lock( 锁 )?为何要使用锁?可重入锁(RLock)防止死锁的加锁机制饱受争议的GIL( ...

  2. Python并发编程之谈谈线程中的“锁机制”(三)

    大家好,并发编程 进入第三篇. 今天我们来讲讲,线程里的锁机制. 本文目录 何为Lock( 锁 )?如何使用Lock( 锁 )?为何要使用锁?可重入锁(RLock)防止死锁的加锁机制饱受争议的GIL( ...

  3. Python 并发编程(三):谈谈 Python 线程中的“锁机制”

    1. 什么是锁? 在开发中,锁 可以理解为通行证. 当你对一段逻辑代码加锁时,意味着在同一时间有且仅能有一个线程在执行这段代码. 在 Python 中的锁可以分为两种: 互斥锁 可重入锁 2. 互斥锁 ...

  4. Java 并发编程解析 | 如何正确理解Java领域中的锁机制,我们一般需要掌握哪些理论知识?

    苍穹之边,浩瀚之挚,眰恦之美: 悟心悟性,善始善终,惟善惟道! -- 朝槿<朝槿兮年说> 写在开头 提起Java领域中的锁,是否有种"道不尽红尘奢恋,诉不完人间恩怨"的 ...

  5. 【数据库】MySQL中的锁机制

    MySQL中的锁机制 数据库锁定机制简单来说,就是数据库为了保证数据的一致性,而使各种共享资源在被并发访问变得有序所设计的一种规则. MySQL 数据库由于其自身架构的特点,存在多种数据存储引擎,每种 ...

  6. Java中的锁机制 -- 乐观锁、悲观锁、自旋锁、可重入锁、读写锁、公平锁、非公平锁、共享锁、独占锁、重量级锁、轻量级锁、偏向锁、分段锁、互斥锁、同步锁、死锁、锁粗化、锁消除

    文章目录 1. Java中的锁机制 1.1 乐观锁 1.2 悲观锁 1.3 自旋锁 1.4 可重入锁(递归锁) 1.5 读写锁 1.6 公平锁 1.7 非公平锁 1.8 共享锁 1.9 独占锁 1.1 ...

  7. 同步锁 php,python线程中同步锁详解

    这篇文章主要为大家详细介绍了python线程中同步锁的相关资料,具有一定的参考价值,感兴趣的小伙伴们可以参考一下 在使用多线程的应用下,如何保证线程安全,以及线程之间的同步,或者访问共享变量等问题是十 ...

  8. 数据库概述09(数据库中的锁机制)

    Innodb中的锁机制 使用数据库的目的在于数据共享,需要考虑数据并发访问问题.解决方案就是锁机制 锁主要包括全局锁.表锁.行锁.乐观锁和悲观锁,需要解决的问题是死锁 存储引擎 存储引擎定义MySQL ...

  9. 数据库中的锁机制(数据库中有哪些锁)

    数据库中的锁机制 锁是网络数据库中的一个非常重要的概念,它主要用于多用户环境下保证数据库完整性和一致性.各种大型数据库所采用的锁的基本理论是一致的,但在具体实现上各有差别.目前,大多数数据库管理系统都 ...

最新文章

  1. 数据结构之图的创建(邻接表)
  2. mt65xx android phone win10驱动,mt65xx android phone驱动下载
  3. 典型关联分析CCA(canonical correlation analysis)
  4. 12个很棒的Spring数据教程来启动您的数据项目
  5. python中none算变量吗_在python中对变量判断是否为None的三种方法总结
  6. 李广难封–有感于团队建设
  7. 地心、南极、太平洋……那些年亚特兰蒂斯“去”过的地方
  8. html游戏 养狗,一起来养狗手游-一起来养狗手游安卓版预约_第一手游网
  9. 雪球网基于沪深300的评论爬虫
  10. 高校375个国家级精品课程
  11. php 12306查询结果,使用php怎么编写一个12306余票查询功能
  12. conversational recommender system论文笔记;推荐系统(recommender system)+对话系统(dialogue system)
  13. Android程序员该如何进阶?,2021Android面经
  14. linux下利用MP4v2封装H264 aac为mp4
  15. linux ksoftirqd进程,ksoftirqd进程导致cpu消耗殆尽
  16. MacM1本地navicat无法连接本地docker的mysql。
  17. 数据库大作业 openGauss程序设计
  18. 利用java swing编写一个简易的计算器,实现了括号,优先级,三角函数,阶乘等功能
  19. 英语口语练习三十之听歌学口语:Boom Clap,你在我的世界里闪闪发光用法
  20. Python调用Linux终端命令---转自本人的私人博客

热门文章

  1. iOS中nil Nil NULL 区别
  2. Can I compile and run Dx11Shader for Maya 2015 on my side?
  3. Android图像开源视图:SmartImageView
  4. 大数据时代的数据管理
  5. 大学毕业生如何应对“没有工作经验”的难题
  6. winfrom中,父窗体中只允许显示一个子窗体的代码怎么写?
  7. 深度好文 — 微服务和API网关限流熔断实现关键逻辑思路
  8. 几个简化算法理解的网站,进来收藏!
  9. 和产品争论MySQL底层如何实现order by的,惨败!
  10. 亿级流量网关设计思路