MST

星途 面试题库

面试题:Python多线程中的锁机制及应用场景

在Python多线程编程中,由于全局解释器锁(GIL)的存在,线程间共享资源可能会出现数据竞争问题。请详细描述Python多线程中锁(如`Lock`、`RLock`)的作用及区别,并且举例说明在一个多线程访问共享字典的场景下,如何正确使用锁来避免数据竞争。
25.0万 热度难度
编程语言Python

知识考点

AI 面试

面试题答案

一键面试

锁的作用

在Python多线程编程中,锁的主要作用是避免多个线程同时访问共享资源,从而防止数据竞争问题。当一个线程获取到锁时,其他线程必须等待锁被释放后才能获取锁并访问共享资源,这样可以确保在同一时刻只有一个线程能够修改共享资源,保证数据的一致性和完整性。

LockRLock的区别

  • Lock(普通锁)
    • 是一种简单的互斥锁。
    • 当一个线程获取锁后,其他线程必须等待该锁被释放才能获取。
    • 如果一个线程尝试获取已经被自己锁定的Lock,会导致死锁,因为它无法再次获取已经持有的锁。
  • RLock(可重入锁)
    • 允许同一个线程多次获取锁,而不会导致死锁。
    • 每次获取锁时,锁的内部计数器加1,每次释放锁时,计数器减1。只有当计数器为0时,锁才会真正被释放,其他线程才能获取。

多线程访问共享字典场景下使用锁避免数据竞争示例

import threading


# 创建共享字典和锁
shared_dict = {}
lock = threading.Lock()
# rlock = threading.RLock()  # 如果使用可重入锁,替换为这行

def update_dict(key, value):
    # 获取锁
    lock.acquire()
    try:
        shared_dict[key] = value
    finally:
        # 释放锁
        lock.release()


# 创建多个线程并启动
threads = []
for i in range(5):
    t = threading.Thread(target=update_dict, args=(i, i * 2))
    threads.append(t)
    t.start()

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

print(shared_dict)

在上述示例中,定义了一个共享字典shared_dict和一个锁lock。在update_dict函数中,通过lock.acquire()获取锁,确保在修改共享字典时其他线程不能同时进行修改,修改完成后通过lock.release()释放锁。如果使用RLock,获取和释放锁的操作与Lock相同,只是同一个线程可以多次获取RLock而不会死锁。