面试题答案
一键面试可能出现的资源竞争场景
在Python多线程环境中,当多个线程同时实例化涉及共享资源访问的类时,可能出现资源竞争。例如,类的初始化方法中对一个共享的计数器变量进行递增操作。如果没有适当的同步机制,可能会出现一个线程读取了计数器的值,还没来得及更新,另一个线程也读取了相同的值,导致更新丢失,最终计数器的值并非预期的正确结果。
底层原理分析
- GIL(全局解释器锁):Python的多线程在CPython解释器中由于GIL的存在,同一时刻只有一个线程能执行Python字节码。这意味着在CPU密集型任务中,多线程并不能真正利用多核优势。但在I/O密集型任务中,线程在等待I/O操作时会释放GIL,其他线程可以趁机执行。然而,对于共享资源的访问,GIL并不能完全解决竞争问题,因为在访问共享资源的代码段内,GIL依然可能导致不同线程在不同时间点访问共享资源,出现数据不一致。
- 锁机制:为了解决资源竞争问题,可以使用锁机制。锁有多种类型,如互斥锁(
threading.Lock
)。当一个线程获取到锁,其他线程就必须等待锁被释放才能获取锁并执行相关代码,从而保证同一时间只有一个线程能访问共享资源。
解决方案及代码示例
使用互斥锁来同步对共享资源的访问。
import threading
# 共享资源
counter = 0
lock = threading.Lock()
class MyClass:
def __init__(self):
global counter
with lock:
# 模拟对共享资源的访问
counter += 1
print(f"实例化MyClass,当前计数器值: {counter}")
def create_instance():
instance = MyClass()
# 创建多个线程实例化MyClass
threads = []
for _ in range(5):
thread = threading.Thread(target=create_instance)
threads.append(thread)
thread.start()
for thread in threads:
thread.join()
在上述代码中,通过with lock
语句,确保了在对共享资源counter
进行操作时,同一时间只有一个线程能进入该代码块,从而避免了资源竞争问题。