90%的人都不知道!Python 中最常用的 5 种线程锁你会用吗?

Python算法鲁棒性设计:5类高频崩溃场景的异常处理实战 在工业级Python算法开发中,'逻辑正确'不等于'生产可用'——空值渗透、类型错配、数值溢出、IO阻塞与并发争抢是导致服务崩溃的五大高频根源。鲁棒性(robustness)本质是面向真实环境的错误响应能力,其核心在于精准异常分类、分层捕获策略与结构化错误治理。本文基于Python原生异常体系,结合try/except/else/finally机制与自定义异常,解析如何将错误转化为可审计、可追溯、可决策的业务信号。覆盖数据清洗、金融计算、推荐系统、风控引擎等典型场景,强调异常即契约、错误即日志、重试即策略的 阅读详情

c0a8ad0cbfe4fafbc669af679f3acbb4.png

作者:云崖君

来源:https://www.cnblogs.com/YunyaSir/p/14963682.html

前言

本文将继续围绕 threading 模块讲解,基本上是纯理论偏多

对于日常开发者来讲很少会使用到本文的内容,但是对框架作者等是必备知识,同时也是高频的面试常见问题

官方文档:https://docs.python.org/zh-cn/3.6/library/threading.html

线程安全

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

线程安全的问题最主要还是由线程切换导致的,比如一个房间(进程)中有10颗糖(资源),除此之外还有3个小人(1个主线程、2个子线程),当小人A吃了3颗糖后被系统强制进行休息时他认为还剩下7颗糖,而当小人B工作后又吃掉了3颗糖,那么当小人A重新上岗时会认为糖还剩下7颗,但是实际上只有4颗了。

上述例子中线程A和线程B的数据不同步,这就是线程安全问题,它可能导致非常严重的意外情况发生,我们按下面这个示例来进行说明。

下面有一个数值num初始值为0,我们开启2条线程:

  • 线程1对num进行一千万次+1的操作

  • 线程2对num进行一千万次-1的操作

结果可能会令人咋舌,num最后并不是我们所想象的结果0:

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 : 669214
# num result : -1849179
# num result : -525674

上面这就是一个非常好的案例,想要解决这个问题就必须通过锁来保障线程切换的时机。

需要我们值得留意的是,在Python基本数据类型中list、tuple、dict本身就是属于线程安全的,所以如果有多个线程对这3种容器做操作时,我们不必考虑线程安全问题。

锁的作用

锁是Python提供给我们能够自行操控线程切换的一种手段,使用锁可以让线程的切换变的有序。

一旦线程的切换变的有序后,各个线程之间对数据的访问、修改就变的可控,所以若要保证线程安全,就必须使用锁。

threading模块中提供了5种最常见的锁,下面是按照功能进行划分:

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

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

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

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

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

1、Lock() 同步锁

基本介绍

Lock锁的称呼有很多,如:

  • 同步锁

  • 互斥锁

它们是什么意思呢?如下所示:

  1. 互斥指的是某一资源同一时刻仅能有一个访问者对其进行访问,具有唯一性和排他性,但是互斥无法限制访问者对资源的访问顺序,即访问是无序的

  2. 同步是指在互斥的基础上(大多数情况),通过其他机制实现访问者对资源的有序访问

  3. 同步其实已经实现了互斥,是互斥的一种更为复杂的实现,因为它在互斥的基础上实现了有序访问的特点

下面是threading模块与同步锁提供的相关方法:

方法描述
threading.Lock()返回一个同步锁对象
lockObject.acquire(blocking=True, timeout=1)上锁,当一个线程在执行被上锁代码块时,将不允许切换到其他线程运行,默认锁失效时间为1秒
lockObject.release()解锁,当一个线程在执行未被上锁代码块时,将允许系统根据策略自行切换到其他线程中运行
lockObject.locaked()判断该锁对象是否处于上锁状态,返回一个布尔值

使用方式

同步锁一次只能放行一个线程,一个被加锁的线程在运行时不会将执行权交出去,只有当该线程被解锁时才会将执行权通过系统调度交由其他线程。

如下所示,使用同步锁解决最上面的问题:

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()的操作,这样会引起死锁造成程序的阻塞,完全不动了,如下所示:

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语句进行上下文管理形式的加锁解锁操作:

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()的操作,但是一定要注意加锁次数和解锁次数必须一致,否则也将引发死锁现象。

下面是threading模块与递归锁提供的相关方法:

方法描述
threading.RLock()返回一个递归锁对象
lockObject.acquire(blocking=True, timeout=1)上锁,当一个线程在执行被上锁代码块时,将不允许切换到其他线程运行,默认锁失效时间为1秒
lockObject.release()解锁,当一个线程在执行未被上锁代码块时,将允许系统根据策略自行切换到其他线程中运行
lockObject.locaked()判断该锁对象是否处于上锁状态,返回一个布尔值

使用方式

以下是递归锁的简单使用,下面这段操作如果使用同步锁则会发生死锁现象,但是递归锁不会:

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语句进行上下文管理形式的加锁解锁操作:

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

3、Condition() 条件锁

基本介绍

条件锁是在递归锁的基础上增加了能够暂停线程运行的功能。并且我们可以使用wait()与notify()来控制线程执行的个数。

注意:条件锁可以自由设定一次放行几个线程。

下面是threading模块与条件锁提供的相关方法:

方法描述
threading.Condition()返回一个条件锁对象
lockObject.acquire(blocking=True, timeout=1)上锁,当一个线程在执行被上锁代码块时,将不允许切换到其他线程运行,默认锁失效时间为1秒
lockObject.release()解锁,当一个线程在执行未被上锁代码块时,将允许系统根据策略自行切换到其他线程中运行
lockObject.wait(timeout=None)将当前线程设置为“等待”状态,只有该线程接到“通知”或者超时时间到期之后才会继续运行,在“等待”状态下的线程将允许系统根据策略自行切换到其他线程中运行
lockObject.wait_for(predicate, timeout=None)将当前线程设置为“等待”状态,只有该线程的predicate返回一个True或者超时时间到期之后才会继续运行,在“等待”状态下的线程将允许系统根据策略自行切换到其他线程中运行。注意:predicate参数应当传入一个可调用对象,且返回结果为bool类型
lockObject.notify(n=1)通知一个当前状态为“等待”的线程继续运行,也可以通过参数n通知多个
lockObject.notify_all()通知所有当前状态为“等待”的线程继续运行

使用方式

下面这个案例会启动10个子线程,并且会立即将10个子线程设置为等待状态。

然后我们可以发送一个或者多个通知,来恢复被等待的子线程继续运行:

import threading

currentRunThreadNumber = 0
maxSubThreadNumber = 10


def task():
    global currentRunThreadNumber
    thName = threading.currentThread().name

    condLock.acquire()  # 上锁
    print("start and wait run thread : %s" % thName)

    condLock.wait()  # 暂停线程运行、等待唤醒
    currentRunThreadNumber += 1
    print("carry on run thread : %s" % thName)

    condLock.release()  # 解锁


if __name__ == "__main__":
    condLock = threading.Condition()

    for i in range(maxSubThreadNumber):
        subThreadIns = threading.Thread(target=task)
        subThreadIns.start()

    while currentRunThreadNumber < maxSubThreadNumber:
        notifyNumber = int(
            input("Please enter the number of threads that need to be notified to run:"))

        condLock.acquire()
        condLock.notify(notifyNumber)  # 放行
        condLock.release()

    print("main thread run end")
    
# 先启动10个子线程,然后这些子线程会全部变为等待状态
# start and wait run thread : Thread-1
# start and wait run thread : Thread-2
# start and wait run thread : Thread-3
# start and wait run thread : Thread-4
# start and wait run thread : Thread-5
# start and wait run thread : Thread-6
# start and wait run thread : Thread-7
# start and wait run thread : Thread-8
# start and wait run thread : Thread-9
# start and wait run thread : Thread-10

# 批量发送通知,放行特定数量的子线程继续运行
# Please enter the number of threads that need to be notified to run:5  # 放行5个
# carry on run thread : Thread-4
# carry on run thread : Thread-3
# carry on run thread : Thread-1
# carry on run thread : Thread-2
# carry on run thread : Thread-5

# Please enter the number of threads that need to be notified to run:5  # 放行5个
# carry on run thread : Thread-8
# carry on run thread : Thread-10
# carry on run thread : Thread-6
# carry on run thread : Thread-9
# carry on run thread : Thread-7

# Please enter the number of threads that need to be notified to run:1
# main thread run end

with语句

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

import threading

currentRunThreadNumber = 0
maxSubThreadNumber = 10


def task():
    global currentRunThreadNumber
    thName = threading.currentThread().name

    with condLock:
        print("start and wait run thread : %s" % thName)
        condLock.wait()  # 暂停线程运行、等待唤醒
        currentRunThreadNumber += 1
        print("carry on run thread : %s" % thName)


if __name__ == "__main__":
    condLock = threading.Condition()

    for i in range(maxSubThreadNumber):
        subThreadIns = threading.Thread(target=task)
        subThreadIns.start()

    while currentRunThreadNumber < maxSubThreadNumber:
        notifyNumber = int(
            input("Please enter the number of threads that need to be notified to run:"))

        with condLock:
            condLock.notify(notifyNumber)  # 放行

    print("main thread run end")

4、Event() 事件锁

基本介绍

事件锁是基于条件锁来做的,它与条件锁的区别在于一次只能放行全部,不能放行任意个数量的子线程继续运行。

我们可以将事件锁看为红绿灯,当红灯时所有子线程都暂停运行,并进入“等待”状态,当绿灯时所有子线程都恢复“运行”。

下面是threading模块与事件锁提供的相关方法:

方法描述
threading.Event()返回一个事件锁对象
lockObject.clear()将事件锁设为红灯状态,即所有线程暂停运行
lockObject.is_set()用来判断当前事件锁状态,红灯为False,绿灯为True
lockObject.set()将事件锁设为绿灯状态,即所有线程恢复运行
lockObject.wait(timeout=None)将当前线程设置为“等待”状态,只有该线程接到“绿灯通知”或者超时时间到期之后才会继续运行,在“等待”状态下的线程将允许系统根据策略自行切换到其他线程中运行

使用方式

事件锁不能利用with语句来进行使用,只能按照常规方式。

如下所示,我们来模拟线程和红绿灯的操作,红灯停,绿灯行:

import threading

maxSubThreadNumber = 3


def task():
    thName = threading.currentThread().name
    print("start and wait run thread : %s" % thName)
    eventLock.wait()  # 暂停运行,等待绿灯
    print("green light, %s carry on run" % thName)
    print("red light, %s stop run" % thName)
    eventLock.wait()  # 暂停运行,等待绿灯
    print("green light, %s carry on run" % thName)
    print("sub thread %s run end" % thName)


if __name__ == "__main__":

    eventLock = threading.Event()

    for i in range(maxSubThreadNumber):
        subThreadIns = threading.Thread(target=task)
        subThreadIns.start()

    eventLock.set()  # 设置为绿灯
    eventLock.clear()  # 设置为红灯
    eventLock.set()  # 设置为绿灯

# start and wait run thread : Thread-1
# start and wait run thread : Thread-2
# start and wait run thread : Thread-3

# green light, Thread-1 carry on run
# red light, Thread-1 stop run
# green light, Thread-1 carry on run
# sub thread Thread-1 run end

# green light, Thread-3 carry on run
# red light, Thread-3 stop run
# green light, Thread-3 carry on run
# sub thread Thread-3 run end

# green light, Thread-2 carry on run
# red light, Thread-2 stop run
# green light, Thread-2 carry on run
# sub thread Thread-2 run end

5、Semaphore() 信号量锁

基本介绍

信号量锁也是根据条件锁来做的,它与条件锁和事件锁的区别如下:

  • 条件锁:一次可以放行任意个处于“等待”状态的线程

  • 事件锁:一次可以放行全部的处于“等待”状态的线程

  • 信号量锁:通过规定,成批的放行特定个处于“上锁”状态的线程

下面是threading模块与信号量锁提供的相关方法:

方法描述
threading.Semaphore()返回一个信号量锁对象
lockObject.acquire(blocking=True, timeout=1)上锁,当一个线程在执行被上锁代码块时,将不允许切换到其他线程运行,默认锁失效时间为1秒
lockObject.release()解锁,当一个线程在执行未被上锁代码块时,将允许系统根据策略自行切换到其他线程中运行

使用方式

以下是使用示例,你可以将它当做一段限宽的路段,每次只能放行相同数量的线程:

import threading
import time

maxSubThreadNumber = 6


def task():
    thName = threading.currentThread().name
    semaLock.acquire()
    print("run sub thread %s" % thName)
    time.sleep(3)
    semaLock.release()


if __name__ == "__main__":
    # 每次只能放行2个
    semaLock = threading.Semaphore(2)

    for i in range(maxSubThreadNumber):
        subThreadIns = threading.Thread(target=task)
        subThreadIns.start()


# run sub thread Thread-1
# run sub thread Thread-2

# run sub thread Thread-3
# run sub thread Thread-4

# run sub thread Thread-6
# run sub thread Thread-5

with语句

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

import threading
import time

maxSubThreadNumber = 6


def task():
    thName = threading.currentThread().name
    with semaLock:
        print("run sub thread %s" % thName)
        time.sleep(3)


if __name__ == "__main__":

    semaLock = threading.Semaphore(2)

    for i in range(maxSubThreadNumber):
        subThreadIns = threading.Thread(target=task)
        subThreadIns.start()

锁关系浅析

上面5种锁可以说都是基于同步锁来做的,这些你都可以从源码中找到答案。

首先来看RLock递归锁,递归锁的实现非常简单,它的内部会维护着一个计数器,当计数器不为0的时候该线程不能被I/O操作和时间轮询机制切换。但是当计数器为0的时候便不会如此了:

def __init__(self):
    self._block = _allocate_lock()
    self._owner = None
    self._count = 0  # 计数器

而Condition条件锁的内部其实是有两把锁的,一把底层锁(同步锁)一把高级锁(递归锁)。

低层锁的解锁方式有两种,使用wait()方法会暂时解开底层锁同时加上一把高级锁,只有当接收到别的线程里的notfiy()后才会解开高级锁和重新上锁低层锁,也就是说条件锁底层是根据同步锁和递归锁的不断切换来进行实现的:

def __init__(self, lock=None):
    if lock is None:
        lock = RLock()  # 可以看到条件锁的内部是基于递归锁,而递归锁又是基于同步锁来做的
    self._lock = lock

    self.acquire = lock.acquire
    self.release = lock.release
    try:
        self._release_save = lock._release_save
    except AttributeError:
        pass
    try:
        self._acquire_restore = lock._acquire_restore
    except AttributeError:
        pass
    try:
        self._is_owned = lock._is_owned
    except AttributeError:
        pass
    self._waiters = _deque()

Event事件锁内部是基于条件锁来做的:

class Event:

    def __init__(self):
        self._cond = Condition(Lock())  # 实例化出了一个条件锁。
        self._flag = False

    def _reset_internal_locks(self):
        # private!  called by Thread._reset_internal_locks by _after_fork()
        self._cond.__init__(Lock())

    def is_set(self):
        """Return true if and only if the internal flag is true."""
        return self._flag

    isSet = is_set

Semaphore信号量锁内部也是基于条件锁来做的:

class Semaphore:

    def __init__(self, value=1):
        if value < 0:
            raise ValueError("semaphore initial value must be >= 0")
        self._cond = Condition(Lock()) # 可以看到,这里是实例化出了一个条件锁
        self._value = value

基本练习题

条件锁的应用

需求:一个空列表,两个线程轮番往里面加值(一个加偶数,一个加奇数),最终让该列表中的值为 1 - 100 ,且是有序排列的。

import threading

lst = []


def even():
    """加偶数"""
    with condLock:
        for i in range(2, 101, 2):
            # 判断当前列表的长度处于2是否能处尽
            # 如果能处尽则代表需要添加奇数
            # 否则就添加偶数
            if len(lst) % 2 != 0:
                # 添偶数
                lst.append(i)      # 先添加值
                condLock.notify()  # 告诉另一个线程,你可以加奇数了,但是这里不会立即交出执行权
                condLock.wait()    # 交出执行权,并等待另一个线程通知加偶数
            else:
                # 添奇数
                condLock.wait()  # 交出执行权,等待另一个线程通知加偶数
                lst.append(i)    
                condLock.notify()
        condLock.notify()


def odd():
    """加奇数"""
    with condLock:
        for i in range(1, 101, 2):
            if len(lst) % 2 == 0:
                lst.append(i)
                condLock.notify()
                condLock.wait()
        condLock.notify()


if __name__ == "__main__":
    condLock = threading.Condition()

    addEvenTask = threading.Thread(target=even)
    addOddTask = threading.Thread(target=odd)

    addEvenTask.start()
    addOddTask.start()

    addEvenTask.join()
    addOddTask.join()

    print(lst)

事件锁的应用

有2个任务线程来扮演李白和杜甫,如何让他们一人一句进行对答?文本如下:

杜甫:老李啊,来喝酒!

李白:老杜啊,不喝了我喝不下了!

杜甫:老李啊,再来一壶?

杜甫:...老李?

李白:呼呼呼...睡着了..

代码如下:

import threading


def libai():
    event.wait()  
    print("李白:老杜啊,不喝了我喝不下了!")
    event.set()
    event.clear()
    event.wait()
    print("李白:呼呼呼...睡着了..")

def dufu():
    print("杜甫:老李啊,来喝酒!")
    event.set()  
    event.clear()
    event.wait()
    print("杜甫:老李啊,再来一壶?")
    print("杜甫:...老李?")
    event.set()


if __name__ == '__main__':

    event = threading.Event()

    t1 = threading.Thread(target=libai)
    t2 = threading.Thread(target=dufu)

    t1.start()
    t2.start()
    t1.join()
    t2.join()

22c83d5a25b0f2ab48441706373d33f1.gif


 

 

 

推荐阅读:

入门: 最全的零基础学Python的问题  | 零基础学了8个月的Python | 实战项目 |学Python就是这条捷径

量化: 定投基金到底能赚多少钱?  | 我用Python对去年800只基金的数据分析

干货:爬取豆瓣短评,电影《后来的我们》 | 38年NBA最佳球员分析|   从万众期待到口碑扑街!唐探3令人失望  | 笑看新倚天屠龙记灯谜答题王 |用Python做个海量小姐姐素描图碟中谍这么火,我用机器学习做个迷你推荐系统电影

趣味:弹球游戏  | 九宫格  | 漂亮的花 | 两百行Python《天天酷跑》游戏!

AI: 会做诗的机器人给图片上色 | 预测收入 | 碟中谍这么火,我用机器学习做个迷你推荐系统电影

小工具: Pdf转Word,轻松搞定表格和水印! | 一键把html网页保存为pdf!|  再见PDF提取收费! | 用90行代码打造最强PDF转换器,word、PPT、excel、markdown、html一键转换 | 制作一款钉钉低价机票提示器! |60行代码做了一个语音壁纸切换器天天看小姐姐!|

年度爆款文案


 

 

 

 

 

 


 

 

 
点阅读原文,领AI全套资料!
PYTHON 120道题目详解(88-90) 120道题目详解 阅读详情

相关推荐

阿里云Ubuntu部署Steam饥荒联机版服务器:从零到多人联机的完整指南

本文详细介绍了在阿里云Ubuntu系统上部署Steam饥荒联机版服务器的完整流程,包括环境准备、SteamCMD安装、服务端配置、Mod管理及后台运行技巧。通过2核4GB的ECS实例配置和端口设置,实现5人流畅联机体验,适合游戏爱好者快速搭建专属服务器。

weixin_29229261的博客 1028

Python线程锁 threading.Lock()介绍

在 Python 中,线程锁(Thread Lock)是一种同步原语,用于在多线程环境中协调线程之间的访问,避免多个线程同时访问共享资源时出现竞态条件(Race Condition)。线程锁确保在任何时刻只有一个线程可以访问特定的资源。为了实现线程锁,Python的threading模块提供了Lock类,下面将先简单介绍下Lock类的一些基础概念和用法。

qq_42310545的博客 2905

ChatGPT设置密钥后Codex免手机验证:配置顺序与身份凭证复用机制

API Key 是一种用于身份识别的凭证,其核心原理是通过预配置的密钥替代交互式登录流程。在开发工具中,密钥认证优先级通常高于会话认证,当本地存在有效密钥时,工具会直接复用该凭证,从而减少重复验证环节。这种机制的技术价值在于提升开发效率与配置一致性,尤其适用于多设备切换、CI/CD 流水线及编程辅助工具等场景。以 Codex 为例,在 ChatGPT 界面提前配置 API 密钥后,Codex 启动时可读取持久化存储的密钥,避免触发手机号验证,实现身份凭证的跨入口复用。

weixin_33940469的博客 499

Python 多线程编程-02-threading 模块-锁的使用

1. 线程同步 1.1 线程同步概念 多线程编程有一个非常重要的方面:同步。此处的同步不是指一起行动,而是协同步调,多个线程按预定的先后次序进行运行。 常见的有两种情况: a)例如某些资源,数据库的某个表格、某个文件,不希望(也不应该)被多个线程同时执行,这样就会产生竞争。那么如何协调这种竞争,可以理解为线程同步。这种内存中的资源可以理解为临界区。 b)需要若干个线程按照特定的顺序完成一组工作,如线程 a 打开文件,输入文字,线程...

一分耕耘一分收获 5563

Apifox CLI + Claude Skills:将接口自动化测试融入ai

基于 Apifox CLI、Claude Code以及Claude Skills组合,实现自然语言触发接口自动化测试。

wwz_0012的博客 599

《生成式AI引发的“认知污染”:社交媒体虚假信息的治理困局》

认知污染与生成式AI“认知污染”指信息环境被大量虚假、误导性内容所充斥,干扰公众对事实的认知判断。在社交媒体时代,虚假信息的生产和传播门槛大幅降低,呈现出工业化、规模化的趋势。近年兴起的生成式人工智能(Generative AI)技术,如大型语言模型(LLM)和深度伪造(deepfake),更是加剧了这一问题。AI可以自动生成看似真实的文本、图像、音视频,将虚假信息批量生产并快速散播到社交平台上。

那谁的博客 5916

再谈Python多线程--threading各类锁

使用多线程的好处是提高执行效率,但同时带来了数据同步的问题。即多个线程同时对一个对象进行操作时,可能会出现资源冲突的问题;在不加锁的情况下,代码可能并未像我们想向的那样工作。举个栗子: import threading n = 2 max_n = 10000 x = 0 def countup(n): global x for i in range(n): ...

上帝De助手 2738

YOLOv11改进-卷积-引入Upsampling by Dynamic DySample 解决传统上采样灵活性问题

现有的上采样方法如等,依赖于动态卷积来生成上采样的内容感知核,但这些方法需要额外的子网络生成动态卷积核计算量较大。尤其是 FADE 和 SAPA 需要高分辨率的特征图作为引导,进一步增加了计算负担,并限制了应用场景。DySample的核心思想是将上采样过程重新定义为点采样(Point Sampling)。通过学习输入特征图中的采样点坐标,DySample 生成内容感知的采样点来对特征图进行重新采样,而不是使用动态卷积核。具体实现步骤如下:​​1. 输入特征图:大小为 C×H×W的输入特征图。

qq_64693987的博客 4663

Python中锁的常见用法

在 Python 中,可以使用线程锁来控制多个线程对共享资源的访问。在 Python 中,可以使用threading模块中的Lock类来创建线程锁。要访问共享资源,需要先获取锁。如果当前锁已经被占用,那么acquire()方法将会阻塞当前线程,直到锁被释放。当完成对共享资源的访问后,需要释放锁,以便其他线程可以继续访问该资源。在 Python 中,可以使用with语句来简化锁的使用。with语句会自动获取和释放锁,避免了手动调用acquire()和release()方法的麻烦。

m0_57021623的博客 2489

SpringBoot+Vue+kkFileView实现文档管理(文档上传、下载、在线预览)

上面在使用OpenOffice实现doc、excel、ppt等文档的管理和预览。除此之外可用kkFileView实现包括且更多文档的预览。

BADAO_LIUMANG_QIZHI的博客 1万+

1 四种防反接电路——multisim仿真

摘要:防反接电路可防止电源反接损坏器件,主要有四种方案:1)二极管串联(低成本,适用小电流);2)整流桥(无极性输入,但效率低);3)保险丝+稳压管(低损耗但需更换);4)MOS管方案(大电流、高效率,主流选择)。选型需考虑电流、压降和成本,MOS管因其低导通电阻(毫欧级)成为大电流应用的首选。口诀:"小电流二极管,大电流用MOS"可快速指导设计。

XU157303764的博客 1576

并发编程实践:进程、线程、锁和threading 模块的全面解析

Python的 threading 模块提供了线程相关的类和方法,可以在 Python 程序中创建和控制多个线程,实现多任务并发执行。

艰难困苦,玉汝于成。 2534

管理类联考——逻辑——真题篇——按知识分类——综合推理

29、某部门抽检了肉制品、白酒、乳制品、干果、蔬菜、水产品、饮料等﹖类商品共521种样品,发现其中合格样品515种,不合格样品6种。已知: (1)蔬菜、白酒中有2种不合格样品。 (2)肉制品、白酒、蔬菜、水产品中有5种不合格样品。 (3)蔬菜、乳制品、干果中有3种不合格样品。 根据上述信息,可以得出以下哪项? A. 乳制品中没有不合格样品。 B. 肉制品中没有不合格样品。 C. 蔬菜中没有不合格样品。 D. 白酒中没有不合格样品。 E. 水产品中没有不合格样品。 31~32题基于以下题干: 某中学举行田径运

stqer的博客 2029

Python入门必学的5个神技,第3个让代码效率提升300%!

Python作为当今最受欢迎的编程语言之一,以其简洁优雅的语法和强大的生态系统赢得了全球开发者的青睐。但对于初学者来说,掌握Python的核心技巧不仅能快速提升编程能力,还能显著提高代码效率。本文将深入介绍5个Python入门必学的"神技",特别是第3个技巧,经过实测能让代码执行效率提升300%!

小筱在线博客 509

廖雪峰Python教程[完整版]

廖雪峰的python教程整理的,已经排好版了,而且还是完整的,适合小白

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

线程锁

from threading import Thread,Lock x= 0 mutex = Lock() def task(): global x mutex.acquire() for i in range(1000000): x = x+1 mutex.release() # 开启线程锁线程就只能一个一个去执行,执行完了再去执行下一个线程,保证数据安全 if name == '...

weixin_30273931的博客 230

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

python创建线程

1 使用threading模块创建线程 import threading,time def progress(): print("thread niame is %s -----"%threading.current_thread().name) if __name__ == '__main__': print('~~主线程开始~~') threads=[threading.Thread(target=progress) for i in range(4)]#创建似四个线程存

星河队长 2118

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

python 创建两个线程交替打印1到100中的奇偶数

一, 利用python 创建两个线程交替打印1到100中的奇偶数 1, 开启两个线程,一个线程专门打印奇数,另外一个线程专门打印偶数 2, python程序如下: import threading import time # 第一个线程,打印奇数 def threada(): for i in range(1, 100+1): if i % 2 != 0: ...

wodedipang_的博客 5694

python-day39(正式学习)

目录 线程锁 死锁问题及递归锁 死锁 递归锁 信号量 GIL全局解释器锁 线程锁 from threading import Thread,Lock x=0 lock=Lock() def test(): ...

Wjx510010104的博客 202

python自动化运维之路~DAY8

                      python自动化运维之路~DAY8                                                作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任。 一.线程进程介绍   为了方便我们队线程和进程的理解,我们来画2组图,方便我们对python中的线程和进程的理解。 其他语言线程与进程的...

weixin_33713707的博客 107

python123分时求和_Python 三程三器的那些事

装饰器1、什么是装饰器装饰器本质是函数,用来给其他函数添加新的功能特点:不修改调用方式、不修改源代码2、装饰器的作用装饰器作用:本质是函数(装饰其他函数)就是为其他函数添加其他功能装饰器必须准寻得原则:不能修改被装饰函数的源代码、不能修改被装饰函数的调用方式实现装饰器知识储备:函数即“变量”高阶函数嵌套函数 高阶函数+潜逃函数=》装饰器3、使用高阶函数模仿装饰器功能1.定义:把一个函数名当做实参传...

weixin_39600510的博客 234

吐血整理:大厂Python学习路线,从青铜到王者,从此打卡学习不迷茫

前言 小编知道 很多朋友都对成为技术大牛有着深深的向往 并有很多技术问题想要解决 因为市面上各种教程质量良莠不齐 而且想要掌握高阶的开发技术 需要耗费大量的时间和精力 现如今每天有数以百万计的人使用 Python ,用户群呈现出指数级增长,几乎没有下降的趋势。 无论在什么行业,为了获取更多的职业发展可能,Python 都成为了隐形的必备技能。 那么,你学 Python 是否遇到过: 初学 Python 一脸懵,想要学习,却不知道学什么; 网上有很多资料,但还是无法...

Summer_4336的博客 917

3大核心技术揭秘:CleanMyWechat如何让微信缓存清理提速500%

当你打开微信PC端的文件管理界面,看到"已用空间38.7GB"的红色警告时,是否感到束手无策?这些悄然积累的缓存文件——群聊图片、短视频、临时文件——正在蚕食你的硬盘空间。普通删除工具面对数十万小文件时如同龟速爬行,而CleanMyWechat通过创新的多线程清理技术,让这场"空间保卫战"变得高效而轻松。 ## 问题引入:被微信吞噬的存储空间 想象一下,你电脑里的微信缓存就像一个无人清理的仓库

gitblog_01185的博客 454

锁

目录 线程锁 死锁问题及递归锁 死锁 递归锁 信号量 GIL全局解释器锁 线程锁 from threading import Thread,Lock x=0 lock=Lock() def test(): lock.acquire() #锁住不让cpu切换 global x for i in range(111100): x+=...

bandi8370的博客 110

【python,threading】python多线程

使用多线程的方式 1、函数式:使用threading模块threading.Thread(e.g target name parameters) 1 import time,threading 2 def loop(): 3 print("thread %s is running..." % threading.current_thread().name) ...

weixin_30838921的博客 65
上一篇: 10 个疯狂的 Python 项目创意
下一篇: 太赞了!最全的Python 处理日期与时间的全面总结!
菜鸟学Python
博客等级 码龄9年 8089粉丝 571原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值