| 锁的作用 
 锁是Python提供给我们能够自行操控线程切换的一种手段,使用锁可以让线程的切换变的有序。
 
 一旦线程的切换变的有序后,各个线程之间对数据的访问、修改就变的可控,所以若要保证线程安全,就必须使用锁。
 
 threading模块中提供了5种最常见的锁,下面是按照功能进行划分:
 
 同步锁:lock(一次只能放行一个)
 
 递归锁:rlock(一次只能放行一个)
 
 条件锁:condition(一次可以放行任意个)
 
 事件锁:event(一次全部放行)
 
 信号量锁:semaphore(一次可以放行特定个)
 
 1、Lock() 同步锁
 
 基本介绍
 
 Lock锁的称呼有很多,如:
 
 同步锁
 
 互斥锁
 
 它们是什么意思呢?如下所示:
 
 互斥指的是某一资源同一时刻仅能有一个访问者对其进行访问,具有唯一性和排他性,但是互斥无法限制访问者对资源的访问顺序,即访问是无序的
 
 同步是指在互斥的基础上(大多数情况),通过其他机制实现访问者对资源的有序访问
 
 同步其实已经实现了互斥,是互斥的一种更为复杂的实现,因为它在互斥的基础上实现了有序访问的特点
 
 使用方式
 
 同步锁一次只能放行一个线程,一个被加锁的线程在运行时不会将执行权交出去,只有当该线程被解锁时才会将执行权通过系统调度交由其他线程。
 
 如下所示,使用同步锁解决最上面的问题:
 
 
 [Python] 纯文本查看 复制代码 import threading
num = 0
def add():
    lock.acquire()
    global num
    for i in range(10_000_000):
        num += 1
    lock.release()
def sub():
    lock.acquire()
    global num
    for i in range(10_000_000):
        num -= 1
    lock.release()
if __name__ == "__main__":
    lock = threading.Lock()
    subThread01 = threading.Thread(target=add)
    subThread02 = threading.Thread(target=sub)
    subThread01.start()
    subThread02.start()
    subThread01.join()
    subThread02.join()
    print("num result : %s" % num)
# 结果三次采集
# num result : 0
# num result : 0
# num result : 0
 这样这个代码就完全变成了串行的状态,对于这种计算密集型I/O业务来说,还不如直接使用串行化单线程执行来得快,所以这个例子仅作为一个示例,不能概述锁真正的用途。
 
 死锁现象
 
 对于同步锁来说,一次acquire()必须对应一次release(),不能出现连续重复使用多次acquire()后再重复使用多次release()的操作,这样会引起死锁造成程序的阻塞,完全不动了,如下所示:
 
 
 [Python] 纯文本查看 复制代码 import threading
num = 0
def add():
    lock.acquire()  # 上锁
    lock.acquire()  # 死锁
    # 不执行
    global num
    for i in range(10_000_000):
        num += 1
    lock.release()
    lock.release()
def sub():
    lock.acquire()  # 上锁
    lock.acquire()  # 死锁
    # 不执行
    global num
    for i in range(10_000_000):
        num -= 1
    lock.release()
    lock.release()
if __name__ == "__main__":
    lock = threading.Lock()
    subThread01 = threading.Thread(target=add)
    subThread02 = threading.Thread(target=sub)
    subThread01.start()
    subThread02.start()
    subThread01.join()
    subThread02.join()
    print("num result : %s" % num)
 with语句
 
 由于threading.Lock()对象中实现了__enter__()与__exit__()方法,故我们可以使用with语句进行上下文管理形式的加锁解锁操作:
 
 
 [Python] 纯文本查看 复制代码 import threading
num = 0
def add():
    with lock:
        # 自动加锁
        global num
        for i in range(10_000_000):
            num += 1
        # 自动解锁
def sub():
    with lock:
        # 自动加锁
        global num
        for i in range(10_000_000):
            num -= 1
        # 自动解锁
if __name__ == "__main__":
    lock = threading.Lock()
    subThread01 = threading.Thread(target=add)
    subThread02 = threading.Thread(target=sub)
    subThread01.start()
    subThread02.start()
    subThread01.join()
    subThread02.join()
    print("num result : %s" % num)
    
# 结果三次采集
# num result : 0
# num result : 0
# num result : 0
 2、RLock() 递归锁
 
 基本介绍
 
 递归锁是同步锁的一个升级版本,在同步锁的基础上可以做到连续重复使用多次acquire()后再重复使用多次release()的操作,但是一定要注意加锁次数和解锁次数必须一致,否则也将引发死锁现象。
 
 使用方式
 
 以下是递归锁的简单使用,下面这段操作如果使用同步锁则会发生死锁现象,但是递归锁不会:
 
 
 [Python] 纯文本查看 复制代码 import threading
num = 0
def add():
    lock.acquire()
    lock.acquire()
    global num
    for i in range(10_000_000):
        num += 1
    lock.release()
    lock.release()
def sub():
    lock.acquire()
    lock.acquire()
    global num
    for i in range(10_000_000):
        num -= 1
    lock.release()
    lock.release()
if __name__ == "__main__":
    lock = threading.RLock()
    subThread01 = threading.Thread(target=add)
    subThread02 = threading.Thread(target=sub)
    subThread01.start()
    subThread02.start()
    subThread01.join()
    subThread02.join()
    print("num result : %s" % num)
# 结果三次采集
# num result : 0
# num result : 0
# num result : 0
 with语句
 
 由于threading.RLock()对象中实现了__enter__()与__exit__()方法,故我们可以使用with语句进行上下文管理形式的加锁解锁操作:
 
 
 [Python] 纯文本查看 复制代码 import threading
num = 0
def add():
    with lock:
        # 自动加锁
        global num
        for i in range(10_000_000):
            num += 1
        # 自动解锁
def sub():
    with lock:
        # 自动加锁
        global num
        for i in range(10_000_000):
            num -= 1
        # 自动解锁
if __name__ == "__main__":
    lock = threading.RLock()
    subThread01 = threading.Thread(target=add)
    subThread02 = threading.Thread(target=sub)
    subThread01.start()
    subThread02.start()
    subThread01.join()
    subThread02.join()
    print("num result : %s" % num)
# 结果三次采集
# num result : 0
# num result : 0
# num result : 0
 
 
 
 【免责声明】本文系转载,原文为公众号Python开发者「云崖君」文章,转载目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责。如涉及作品内容、版权和其它问题,请在30日内与联系我们,我们会予以更改或删除相关文章,以保证您的权益! 
 |