MST

星途 面试题库

面试题:Python多线程锁机制在复杂场景下的应用

假设你有一个Python多线程程序,多个线程需要对一个复杂的数据结构(例如嵌套字典和列表)进行读写操作,同时要保证数据的一致性,如何合理地使用锁机制来避免数据竞争?请详细说明设计思路和代码实现框架。
10.9万 热度难度
编程语言Python

知识考点

AI 面试

面试题答案

一键面试

设计思路

  1. 选择锁类型:在Python中,threading.Lock 是最基本的锁类型,适用于这种场景。我们需要一个锁对象来保护对复杂数据结构的读写操作。
  2. 加锁位置:在对数据结构进行读或写操作之前获取锁,操作完成后释放锁。这样可以确保同一时间只有一个线程能够访问和修改数据结构,从而避免数据竞争。
  3. 考虑性能:如果读操作远远多于写操作,可以考虑使用 threading.RLock(可重入锁) 或者 threading.Condition 结合 threading.Lock 实现读写锁(读者 - 写者锁)来提高性能。读操作时允许多个线程同时获取锁进行读取,写操作时则独占锁。

代码实现框架

import threading


# 复杂数据结构
data = {
    "key1": [1, 2, 3],
    "key2": {
        "sub_key1": "value1",
        "sub_key2": "value2"
    }
}

# 创建锁对象
lock = threading.Lock()


# 写操作函数
def write_data(new_data):
    global data
    lock.acquire()
    try:
        data = new_data
    finally:
        lock.release()


# 读操作函数
def read_data():
    lock.acquire()
    try:
        return data.copy()
    finally:
        lock.release()


# 示例线程函数
def example_thread():
    new_data = {
        "key1": [4, 5, 6],
        "key2": {
            "sub_key1": "new_value1",
            "sub_key2": "new_value2"
        }
    }
    write_data(new_data)
    result = read_data()
    print(result)


# 创建并启动线程
threads = []
for _ in range(5):
    t = threading.Thread(target=example_thread)
    threads.append(t)
    t.start()


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

上述代码中:

  1. lock 是一个 threading.Lock 对象,用于保护对 data 的操作。
  2. write_data 函数在更新 data 之前获取锁,更新完成后释放锁。
  3. read_data 函数在读取 data 之前获取锁,读取完成后释放锁,并返回 data 的副本以避免外部对原数据结构的意外修改。
  4. example_thread 函数模拟了一个线程的操作,先进行写操作,再进行读操作。
  5. 创建多个线程并启动,最后等待所有线程完成。

如果读操作远多于写操作,可以使用如下基于 threading.Condition 实现读写锁的示例代码框架:

import threading


# 复杂数据结构
data = {
    "key1": [1, 2, 3],
    "key2": {
        "sub_key1": "value1",
        "sub_key2": "value2"
    }
}

# 创建Condition对象
condition = threading.Condition()
read_count = 0


# 写操作函数
def write_data(new_data):
    global data
    with condition:
        condition.wait_for(lambda: read_count == 0)
        data = new_data


# 读操作函数
def read_data():
    global read_count
    with condition:
        read_count += 1
        condition.notify_all()
        try:
            return data.copy()
        finally:
            read_count -= 1
            if read_count == 0:
                condition.notify_all()


# 示例线程函数
def example_thread():
    new_data = {
        "key1": [4, 5, 6],
        "key2": {
            "sub_key1": "new_value1",
            "sub_key2": "new_value2"
        }
    }
    write_data(new_data)
    result = read_data()
    print(result)


# 创建并启动线程
threads = []
for _ in range(5):
    t = threading.Thread(target=example_thread)
    threads.append(t)
    t.start()


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

在这个实现中,Condition 对象用于协调读写操作。写操作等待没有读者时执行,读操作增加读者计数并通知其他等待的线程。当最后一个读者离开时,通知等待的写者。