MST
星途 面试题库

面试题:Python中信号量与锁在多线程编程中的应用差异

在Python的多线程编程场景下,请阐述信号量(Semaphore)与锁(Lock)在应用上的主要差异,并各举一个简单代码示例说明如何使用它们来控制资源访问。
45.3万 热度难度
编程语言Python

知识考点

AI 面试

面试题答案

一键面试

信号量(Semaphore)与锁(Lock)的主要差异

  1. 控制访问数量
    • 锁(Lock):本质上是二元信号量,只允许一个线程进入临界区,用于保证同一时间只有一个线程能访问共享资源,就像一把钥匙对应一扇门,只有拿到钥匙(获取锁)的线程才能进入房间(访问资源)。
    • 信号量(Semaphore):可以允许一定数量的线程同时进入临界区,通过设置内部计数器来控制同时访问资源的线程数量,例如可以想象为有多个房间,信号量的计数器表示房间数量,有相应数量的钥匙,多个线程可以同时拿到钥匙进入房间。
  2. 适用场景
    • 锁(Lock):适用于资源只能被一个线程独占访问的场景,如对共享文件的写入操作,避免数据冲突。
    • 信号量(Semaphore):适用于资源允许一定数量线程同时访问的场景,例如数据库连接池,允许一定数量的线程同时获取连接进行数据库操作。

代码示例

  1. 锁(Lock)示例
import threading


# 共享资源
counter = 0
lock = threading.Lock()


def increment():
    global counter
    # 获取锁
    lock.acquire()
    try:
        counter = counter + 1
    finally:
        # 释放锁
        lock.release()


threads = []
for _ in range(10):
    t = threading.Thread(target=increment)
    threads.append(t)
    t.start()

for t in threads:
    t.join()

print(f"Final counter value: {counter}")

在这个示例中,lock.acquire() 获取锁,确保只有一个线程能修改 counterlock.release() 释放锁,让其他线程有机会获取锁并修改 counter

  1. 信号量(Semaphore)示例
import threading


# 创建一个信号量,允许3个线程同时访问
semaphore = threading.Semaphore(3)


def access_resource():
    # 获取信号量
    semaphore.acquire()
    try:
        print(f"{threading.current_thread().name} has access to the resource.")
    finally:
        # 释放信号量
        semaphore.release()


threads = []
for i in range(10):
    t = threading.Thread(target=access_resource)
    threads.append(t)
    t.start()

for t in threads:
    t.join()

在这个示例中,semaphore.acquire() 获取信号量,当信号量内部计数器大于0时,线程获取成功并将计数器减1,当计数器为0时,其他线程需要等待。semaphore.release() 释放信号量,将计数器加1,允许其他等待的线程获取信号量并访问资源。