面试题答案
一键面试可能出现资源竞争的场景
假设我们有一个简单的Web应用,用于统计网站的访问次数。在多线程环境下,多个线程可能同时尝试增加这个访问次数的计数器。例如:
import threading
counter = 0
def increment():
global counter
for _ in range(100000):
counter = counter + 1
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}")
在上述代码中,如果多个线程同时执行counter = counter + 1
这行代码,由于这不是一个原子操作(实际上分为读取counter
值、增加1、再写回counter
值三个步骤),就可能出现资源竞争。比如线程A读取了counter
的值为10,线程B也读取了counter
的值为10,然后它们都增加1并写回,这样就丢失了一次增加操作,最终结果会小于预期的1000000(10个线程,每个线程增加100000次)。
使用锁机制解决问题
可以使用threading.Lock
来解决这个问题。修改后的代码如下:
import threading
counter = 0
lock = threading.Lock()
def increment():
global counter
for _ in range(100000):
with lock:
counter = counter + 1
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}")
在上述代码中,with lock:
语句创建了一个上下文管理器,当进入这个上下文时,锁被获取,当离开上下文时,锁被释放。这样,在任何时刻只有一个线程能够执行counter = counter + 1
这行代码,从而避免了资源竞争,确保最终的counter
值是准确的1000000。