python 线程锁

本文介绍了Python多线程编程中的线程锁,包括互斥锁Lock、递归锁RLock、条件锁Condition、事件锁Event和信号量锁Semaphore的使用方法和案例,探讨了死锁现象以及如何避免死锁。
摘要由CSDN通过智能技术生成

目录

1、线程安全介绍

2、threading5种常见锁

2.1 同步锁(互斥锁)Lock

(1) 基本介绍及相关方法

(2) 给案例加lock锁

(3)with语句

2.2 递归锁Rlock

(1)基本介绍及相关方法

(2) 给案例加递归锁

(3) with 语句

2.3 条件锁Condition

(1)基本介绍和方法

(2)with语句

(3)案例

2.4 事件锁Event

(1)基本介绍和方法

(2)使用方式

(3)案例

2.5 信号量锁Semaphore

(1)基本介绍和方法

(2)案例

(3)with语句

3、死锁现象

4、总结

1、线程安全介绍

线程安全的问题最主要还是由线程切换导致的。

线程安全是多线程或多进程编程中的一个概念,在拥有共享数据的多条线程并行执行的程序中,线程安全的代码会通过同步机制保证各个线程都可以正常且正确的执行,不会出现数据污染等意外情况。

线程不安全案例:

创建2个线程:线程1对num进行一千万次+1的操作;线程2对num进行一千万次-1的操作

import threading

num = 0

def add():
    global num
    for i in range(10_000_000):
        num += 1

def sub():
    global num
    for i in range(10_000_000):
        num -= 1

if __name__ == "__main__":
    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 : 645898
num result : -331131
num result : 901713

num最后并不是我们所想象的结果0。因此需要通过来保障线程切换的时机。

2、threading5种常见锁

threading模块中提供了5种最常见的锁:

  • 同步锁:lock(一次只能放行一个)

  • 递归锁:rlock(一次只能放行一个)

  • 条件锁:condition(一次可以放行任意个)

  • 事件锁:event(一次全部放行)

  • 信号量锁:semaphore(一次可以放行特定个)

2.1 同步锁(互斥锁)Lock

(1) 基本介绍及相关方法
  • 互斥指的是某一资源同一时刻仅能有一个访问者对其进行访问,具有唯一性和排他性,但是互斥无法限制访问者对资源的访问顺序,即访问是无序的
  • 同步是指在互斥的基础上(大多数情况),通过其他机制实现访问者对资源的有序访问
  • 同步其实已经实现了互斥,是互斥的一种更为复杂的实现,因为它在互斥的基础上实现了有序访问的特点
# 生成互斥锁对象
lock = threading.Lock()

# 获取锁,未获取到程序将会阻塞(当一个线程在执行被上锁的代码块时,将不允许切换到其他线程)
lock.acquire()

# 释放锁
lock.release()

# 判断该锁对象是否处于上锁状态
lock.locked()
(2) 给案例加lock锁
import threading

num = 0
lock = threading.Lock()  # 生成互斥锁对象

def add():
    global num
    lock.acquire()   # 上锁
    for i in range(10_000_000):
        num += 1
    lock.release()   # 释放锁

def sub():
    global num
    lock.acquire()  # 上锁
    for i in range(10_000_000):
        num -= 1
    lock.release()    # 释放锁

if __name__ == "__main__":
    subThread01 = threading.Thread(target=add)
    subThread02 = threading.Thread(target=sub)

    subThread01.start()
    subThread02.start()

    subThread01.join()
    subThread02.join()

    print("num result : %s" % num)

执行上述代码,每次结果均为0。

上述代码完全变成了串行的状态,对于这种计算密集型I/O业务来说,还不如直接使用串行化单线程执行来得快,所以这个例子仅作为一个示例,不能概述锁真正的用途。

(3)with语句

由于threading.Lock()对象中实现了enter__()与__exit()方法,故可以使用with语句进行上下文管理形式的加锁解锁操作:

import threading

num = 0
lock = threading.Lock()


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__":
    subThread01 = threading.Thread(target=add)
    subThread02 = threading.Thread(target=sub)

    subThread01.start()
    subThread02.start()

    subThread01.join()
    subThread02.join()

    print("num result : %s" % num
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值