面试题答案
一键面试设计思路
- 选择锁类型:在Python中,
threading.Lock
是最基本的锁类型,适用于这种场景。我们需要一个锁对象来保护对复杂数据结构的读写操作。 - 加锁位置:在对数据结构进行读或写操作之前获取锁,操作完成后释放锁。这样可以确保同一时间只有一个线程能够访问和修改数据结构,从而避免数据竞争。
- 考虑性能:如果读操作远远多于写操作,可以考虑使用
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()
上述代码中:
lock
是一个threading.Lock
对象,用于保护对data
的操作。write_data
函数在更新data
之前获取锁,更新完成后释放锁。read_data
函数在读取data
之前获取锁,读取完成后释放锁,并返回data
的副本以避免外部对原数据结构的意外修改。example_thread
函数模拟了一个线程的操作,先进行写操作,再进行读操作。- 创建多个线程并启动,最后等待所有线程完成。
如果读操作远多于写操作,可以使用如下基于 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
对象用于协调读写操作。写操作等待没有读者时执行,读操作增加读者计数并通知其他等待的线程。当最后一个读者离开时,通知等待的写者。