面试题答案
一键面试避免资源竞争的方法
- 锁机制:
- 互斥锁(Mutex):线程或异步任务在访问共享资源前获取锁,访问完后释放锁,同一时间只有一个线程或任务能持有锁,从而避免竞争。
- 信号量(Semaphore):与互斥锁类似,但可以允许多个线程或任务同时访问共享资源,通过设置信号量的初始值来控制同时访问的数量。
- 队列:使用队列来传递数据,线程或异步任务将数据放入队列,其他线程或任务从队列中取出数据进行处理,避免直接访问共享数据。
- 线程本地存储(TLS):每个线程有自己独立的存储空间,避免不同线程之间的数据竞争。在异步编程中,可以使用类似的上下文管理机制。
银行转账场景代码示例
import threading
import asyncio
# 定义账户余额
account_balance = 1000
# 创建互斥锁
lock = threading.Lock()
# 线程函数实现转账
def transfer_thread(amount):
global account_balance
with lock:
if account_balance >= amount:
account_balance -= amount
print(f"Thread transferred {amount}, new balance: {account_balance}")
else:
print("Insufficient balance for thread transfer")
# 异步函数实现转账
async def transfer_async(amount):
global account_balance
async with asyncio.Lock():
if account_balance >= amount:
account_balance -= amount
print(f"Async transferred {amount}, new balance: {account_balance}")
else:
print("Insufficient balance for async transfer")
# 创建线程
threads = []
for _ in range(3):
t = threading.Thread(target=transfer_thread, args=(200,))
threads.append(t)
t.start()
# 等待所有线程完成
for t in threads:
t.join()
# 创建异步任务
async def main():
tasks = []
for _ in range(3):
task = asyncio.create_task(transfer_async(200))
tasks.append(task)
await asyncio.gather(*tasks)
asyncio.run(main())
在上述代码中,对于线程操作,使用 threading.Lock
来确保在修改账户余额时不会出现资源竞争。对于异步操作,使用 asyncio.Lock
达到相同的目的。通过这种方式,无论是多线程还是异步任务,在进行银行转账操作时都能有效管理资源,防止数据不一致。