Python锁机制如何理解,RLock()与Lock()有何不同

Admin 2022-08-03 群英技术资讯 307 次浏览

在这篇文章中,我们来学习一下“Python锁机制如何理解,RLock()与Lock()有何不同”的相关知识,下文有详细的讲解,易于大家学习和理解,有需要的朋友可以借鉴参考,下面就请大家跟着小编的思路一起来学习一下吧。

什么是锁机制?

要回答这个问题,我们需要知道为什么需要使用锁机制。前面我们谈到一个进程内的多个线程的某些资源是共享的,这也是线程的一大优势,但是也随之带来一个问题,即当两个及两个以上的线程同时访问共享资源时,如果此时没有预设对应的同步机制,就可能带来同一时刻多个线程同时访问同一个共享资源,即出现竞态,多数情况下我们是不希望出现这样的情况的,那么怎么避免呢?

Lock() 管理线程

先看一段代码:

import threading
import time
resource = 0
count = 1000000
resource_lock = threading.Lock()
def increment():
    global resource
    for i in range(count):
        resource += 1
def decerment():
    global resource
    for i in range(count):
        resource -= 1
increment_thread = threading.Thread(target=increment)
decerment_thread = threading.Thread(target=decerment)
increment_thread.start()
decerment_thread.start()
increment_thread.join()
decerment_thread.join()
print(resource)

运行截图如下:

运行结果

当我们多次运行时,可以看到最终的结果都几乎不等于我们期待的值即resource初始值0

为什么呢? 原因就是因为 += 和 -=并不是原子操作。

可以使用dis模块查看字节码:

import dis
def add(total):
    total += 1
def desc(total):
    total -= 1
total = 0
print(dis.dis(add))
print(dis.dis(desc))
# 运行结果:
#   3           0 LOAD_FAST                0 (total)
#               3 LOAD_CONST               1 (1)
#               6 INPLACE_ADD
#               7 STORE_FAST               0 (total)
#              10 LOAD_CONST               0 (None)
#              13 RETURN_VALUE
# None
#   5           0 LOAD_FAST                0 (total)
#               3 LOAD_CONST               1 (1)
#               6 INPLACE_SUBTRACT
#               7 STORE_FAST               0 (total)
#              10 LOAD_CONST               0 (None)
#              13 RETURN_VALUE
# None

那么如何保证初始值为0呢? 我们可以利用Lock(),代码如下:

import threading
import time
resource = 0
count = 1000000
resource_lock = threading.Lock()
def increment():
    global resource
    for i in range(count):
        resource_lock.acquire()
        resource += 1
        resource_lock.release()
def decerment():
    global resource
    for i in range(count):
        resource_lock.acquire()
        resource -= 1
        resource_lock.release()
increment_thread = threading.Thread(target=increment)
decerment_thread = threading.Thread(target=decerment)
increment_thread.start()
decerment_thread.start()
increment_thread.join()
decerment_thread.join()
print(resource)

运行截图如下:

运行结果

从运行结果可以看到,不论我们运行多少次改代码,其resource的值都为初始值0, 这就是Lock()的功劳,即它可以将某一时刻的访问限定在单个线程或者单个类型的线程上,在访问锁定的共享资源时,必须要现获取对应的锁才能访问,即要等待其他线程释放资源,即resource_lock.release()当然为了防止我们对某个资源锁定后,忘记释放锁,导致死锁,我们可以利用上下文管理器管理锁实现同样的效果:

import threading
import time
resource = 0
count = 1000000
resource_lock = threading.Lock()
def increment():
    global resource
    for i in range(count):
        with resource_lock:
                resource += 1
def decerment():
    global resource
    for i in range(count):
        with resource_lock:
                resource -= 1
increment_thread = threading.Thread(target=increment)
decerment_thread = threading.Thread(target=decerment)
increment_thread.start()
decerment_thread.start()

RLock() 与Lock()的区别

我们需要知道Lock()作为一个基本的锁对象,一次只能一个锁定,其余锁请求,需等待锁释放后才能获取,否则会发生死锁:

import threading
resource.lock = threading.lock()
resource = 0
resource.lock.acquire()
resource.lock.acquire()
resource += 1
resource.lock.release()
resource.lock.release()

为解决同一线程中不能多次请求同一资源的问题,python提供了“可重入锁”:threading.RLockRLock内部维护着一个Lock和一个counter变量,counter记录了acquire的次数,从而使得资源可以被多次acquire

直到一个线程所有的acquire都被release,其他的线程才能获得资源 。用法和threading.Lock类相同,即比如递归锁的使用:

import threading
lock = threading.RLock()
def dosomething(lock):
    lock.acquire()
    # do something
    lock.release()
lock.acquire()
dosomething(lock)
lock.release()

以上就是关于“Python锁机制如何理解,RLock()与Lock()有何不同”的相关知识,感谢各位的阅读,想要掌握这篇文章的知识点还需要大家自己动手实践使用过才能领会,如果想了解更多相关内容的文章,欢迎关注群英网络,小编每天都会为大家更新不同的知识。
群英智防CDN,智能加速解决方案
标签: Python锁机制

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:mmqy2019@163.com进行举报,并提供相关证据,查实之后,将立刻删除涉嫌侵权内容。

猜你喜欢

成为群英会员,开启智能安全云计算之旅

立即注册
专业资深工程师驻守
7X24小时快速响应
一站式无忧技术支持
免费备案服务
免费拨打  400-678-4567
免费拨打  400-678-4567 免费拨打 400-678-4567 或 0668-2555555
在线客服
微信公众号
返回顶部
返回顶部 返回顶部
在线客服
在线客服