threading.Semaphore和threading.Lock

threading.Semaphore

定义:
threading.Semaphore 是 Python 中的线程同步原语,用于控制并发线程的访问数量。Semaphore 类可以创建一个计数器,该计数器限制了同时获取资源的线程数量。其中的两个主要方法是 acquire() 和 release()。
方法:
acquire(): 当调用 acquire() 方法时,线程会尝试获取资源的访问权限。如果当前计数器的值大于零,线程可以成功获取资源并将计数器减一;如果当前计数器的值为零,线程将被阻塞,直到有其他线程释放资源。
release(): 当线程使用完资源后,应该调用 release() 方法释放资源的访问权限,这将使计数器的值加一,允许其他线程获取资源。
示例
演示了 Semaphore 的使用:

import threading

semaphore = threading.Semaphore(2)  # 创建一个允许两个线程同时访问的 Semaphore

def worker():
    print('Worker is acquiring semaphore')
    semaphore.acquire()  # 获取资源的访问权限
    print('Worker has acquired semaphore')
    # 执行需要访问资源的操作
    print('Worker is releasing semaphore')
    semaphore.release()  # 释放资源的访问权限
    print('Worker has released semaphore')


# 创建多个线程
for i in range(5):
    t = threading.Thread(target=worker)
    t.start()

Semaphore 的初始计数器值为 2,因此最多允许两个线程同时获取资源的访问权限。其他线程会在调用 acquire() 方法时被阻塞,直到有线程调用 release() 方法释放资源。

使用 Semaphore 可以有效地控制并发线程的访问,例如限制同时访问某个共享资源的线程数量,或者控制并发请求的频率等。

threading.Lock

Python 中的线程锁,用于在多线程环境下保护共享资源,防止多个线程同时访问造成数据不一致或竞争条件的问题。下面是关于 threading.Lock 的详细解释和使用方法:

创建锁对象

import threading

lock = threading.Lock()

获取锁

在进入临界区之前,需要先获取锁。如果锁已经被其他线程获取,则当前线程会阻塞,直到获取到锁为止。
使用 acquire() 方法获取锁:

lock.acquire()

或者使用 with 语句来自动获取和释放锁:

with lock:
    # 执行临界区代码

释放锁

在完成临界区代码的执行后,需要释放锁,让其他线程可以获取锁并执行临界区代码。
使用 release() 方法释放锁:

lock.release()

或者通过 with 语句自动释放锁。
锁的嵌套

同一个线程可以多次获取同一个锁,但需要相应地释放相同次数的锁才能完全释放。
如果没有正确地释放锁的次数与获取锁的次数匹配,可能会导致死锁或其他线程同步问题。

import threading

lock = threading.Lock()

def thread_func():
    with lock:
        # 执行临界区代码
        print("Thread acquired lock")

# 创建多个线程
threads = []
for _ in range(5):
    t = threading.Thread(target=thread_func)
    threads.append(t)
    t.start()

# 等待所有线程执行完毕
for t in threads:
    t.join()

在使用 threading.Lock 时,需要注意以下几点:

1.锁的作用范围应该尽量缩小,只在必要的代码块内使用,避免不必要的线程阻塞。
2.在使用锁的同时,需要注意避免死锁(多个线程相互等待对方释放锁的情况)和竞争条件(多个线程同时修改共享资源的情况)。
3.尽量使用 with 语句来自动获取和释放锁,以避免忘记释放锁的情况发生。
4.锁的性能开销较大,过多地使用锁可能会影响程序的性能。因此,在设计多线程程序时,应该合理使用锁来平衡线程安全和性能的需求。

区别

threading.Lock 和 threading.Semaphore 都是用于线程同步的工具,但在某些方面有一些区别。

功能差异

threading.Lock 是最基本的线程锁,只有两种状态:锁定(locked)和非锁定(unlocked)。一次只允许一个线程获取锁并执行临界区代码。
threading.Semaphore 是一个计数信号量,可以设置初始计数值,并且可以允许多个线程同时获取资源。当计数值大于 1 时,允许多个线程同时执行临界区代码。
计数

threading.Lock 只有两种状态,因此只能用于控制同一时刻只有一个线程访问临界区。
threading.Semaphore 可以通过设置计数值来控制同时访问临界区的线程数量。计数值可以大于 1,允许多个线程同时访问。
释放锁的方式

threading.Lock 必须由获取锁的线程来释放锁,即只有获得锁的线程才能解锁。
threading.Semaphore 可以由任意线程来释放信号量,即可以由其他线程来解锁。
选择使用哪种工具取决于具体的需求。如果只需要控制同一时刻只有一个线程访问临界区,可以使用 threading.Lock。如果需要控制同时访问临界区的线程数量,可以使用 threading.Semaphore。

猜你喜欢

转载自blog.csdn.net/liulanba/article/details/130812056