面试题答案
一键面试同步与通信策略设计
- 锁机制
- 互斥锁(Mutex):用于保护共享资源,避免多个线程或进程同时访问。例如,在对共享数据结构(如字典、列表)进行读写操作时,在操作前后加锁。
import threading lock = threading.Lock() shared_dict = {} def update_dict(key, value): lock.acquire() try: shared_dict[key] = value finally: lock.release()
- 递归锁(RLock):允许同一个线程多次获取锁,防止死锁。适用于一个线程内需要多次获取同一把锁的情况。
rlock = threading.RLock() def recursive_function(): rlock.acquire() try: # 一些操作 recursive_function() finally: rlock.release()
- 信号量(Semaphore)
- 用于控制同时访问共享资源的线程或进程数量。比如,限制同时连接数据库的线程数。
semaphore = threading.Semaphore(5) # 最多允许5个线程同时访问 def access_database(): semaphore.acquire() try: # 数据库操作 pass finally: semaphore.release()
- 队列(Queue)
- 线程队列(Queue.Queue):用于线程间通信,线程安全。生产者 - 消费者模型中常用。
from queue import Queue task_queue = Queue() def producer(): for i in range(10): task_queue.put(i) def consumer(): while True: item = task_queue.get() if item is None: break # 处理任务 task_queue.task_done()
- 进程队列(multiprocessing.Queue):用于进程间通信,同样线程安全。
from multiprocessing import Queue process_queue = Queue() def process_producer(): for i in range(10): process_queue.put(i) def process_consumer(): while True: item = process_queue.get() if item is None: break # 处理任务 process_queue.task_done()
- 事件(Event)
- 用于线程或进程间的简单同步。例如,一个线程等待另一个线程完成某个操作后再继续执行。
event = threading.Event() def waiting_thread(): event.wait() # 等待事件被设置后执行的操作 def signaling_thread(): # 一些操作 event.set()
- 条件变量(Condition)
- 比锁更复杂,允许线程在满足特定条件时等待或唤醒。比如,在生产者 - 消费者模型中,当队列满时生产者等待,队列空时消费者等待。
condition = threading.Condition() queue = [] def producer(): with condition: while len(queue) >= 10: # 假设队列最大容量为10 condition.wait() queue.append('new item') condition.notify() def consumer(): with condition: while not queue: condition.wait() item = queue.pop(0) condition.notify()
高并发性能瓶颈及解决方案
- 锁竞争
- 性能瓶颈:过多线程或进程竞争同一把锁,导致大量时间浪费在等待锁上,降低系统并发性能。
- 解决方案:
- 减少锁粒度:将大的锁保护区域分解为多个小的锁保护区域,减少锁竞争范围。
- 锁分离:对于读多写少的场景,使用读写锁(
threading.RLock
或multiprocessing.RLock
),允许多个线程同时读,写操作时加独占锁。
- 队列性能
- 性能瓶颈:高并发下,队列的入队和出队操作可能成为性能瓶颈,特别是在处理大量数据时。
- 解决方案:
- 使用无锁队列:在一些特定场景下,如使用
collections.deque
并结合线程/进程安全的操作方式,可提高队列操作性能。 - 优化队列大小:根据实际应用场景,合理调整队列大小,避免队列过小频繁触发等待,或过大占用过多内存。
- 使用无锁队列:在一些特定场景下,如使用
- 进程间通信开销
- 性能瓶颈:进程间通信(如使用
multiprocessing.Queue
)相对线程间通信开销更大,在高并发场景下,频繁的进程间通信会降低系统性能。 - 解决方案:
- 减少不必要的通信:尽量在进程内部处理数据,减少进程间数据传递的频率。
- 使用共享内存:对于一些需要频繁共享的数据,使用
multiprocessing.shared_memory
模块创建共享内存对象,提高数据共享效率。
- 性能瓶颈:进程间通信(如使用