MST

星途 面试题库

面试题:Python线程与进程的同步机制优化

在一个Python应用中,同时使用了多线程和多进程,线程之间需要共享数据,进程之间也有数据交互需求。请设计一套合理的同步机制,以避免数据竞争和死锁问题,并详细说明在不同场景下如何选择和使用锁、信号量、队列等同步工具。
17.2万 热度难度
编程语言Python

知识考点

AI 面试

面试题答案

一键面试

线程间共享数据同步机制

  1. 锁(Lock
    • 适用场景:当需要保护共享资源,确保同一时间只有一个线程能访问该资源时使用。例如,多个线程同时操作一个全局变量,防止数据竞争。
    • 使用示例
import threading

# 创建锁
lock = threading.Lock()
shared_variable = 0

def increment():
    global shared_variable
    with lock:
        shared_variable += 1
  1. 信号量(Semaphore
    • 适用场景:当需要限制同时访问共享资源的线程数量时使用。比如,限制同时访问数据库连接池中的连接数量。
    • 使用示例
import threading

# 创建信号量,允许最多3个线程同时访问
semaphore = threading.Semaphore(3)

def access_resource():
    with semaphore:
        # 访问共享资源的代码
        pass
  1. 队列(Queue
    • 适用场景:在线程间传递数据时非常有用,它是线程安全的。可以用于生产者 - 消费者模式,避免数据竞争。
    • 使用示例
import threading
import queue

# 创建队列
q = queue.Queue()

def producer():
    for i in range(5):
        q.put(i)

def consumer():
    while True:
        item = q.get()
        if item is None:
            break
        # 处理数据
        print(f"Consumed {item}")
        q.task_done()

进程间数据交互与同步机制

  1. 锁(multiprocessing.Lock
    • 适用场景:与线程锁类似,用于保护进程间共享资源,防止数据竞争。例如,多个进程同时写入一个文件。
    • 使用示例
import multiprocessing

# 创建锁
lock = multiprocessing.Lock()
shared_value = multiprocessing.Value('i', 0)

def increment_process():
    global shared_value
    with lock:
        shared_value.value += 1
  1. 信号量(multiprocessing.Semaphore
    • 适用场景:限制同时访问共享资源的进程数量,例如限制同时访问系统硬件资源的进程数。
    • 使用示例
import multiprocessing

# 创建信号量,允许最多2个进程同时访问
semaphore = multiprocessing.Semaphore(2)

def access_shared_resource():
    with semaphore:
        # 访问共享资源的代码
        pass
  1. 队列(multiprocessing.Queue
    • 适用场景:用于进程间安全地传递数据,是进程安全的。常用于进程间的生产者 - 消费者模式。
    • 使用示例
import multiprocessing

# 创建队列
q = multiprocessing.Queue()

def producer_process():
    for i in range(5):
        q.put(i)

def consumer_process():
    while True:
        item = q.get()
        if item is None:
            break
        # 处理数据
        print(f"Consumed {item}")
        q.task_done()
  1. 管道(multiprocessing.Pipe
    • 适用场景:用于两个进程之间进行数据通信,提供了一个双向的通信通道。
    • 使用示例
import multiprocessing

def sender(conn):
    conn.send('Hello from sender')
    conn.close()

def receiver(conn):
    message = conn.recv()
    print(f"Received: {message}")
    conn.close()

if __name__ == '__main__':
    parent_conn, child_conn = multiprocessing.Pipe()
    p1 = multiprocessing.Process(target = sender, args=(child_conn,))
    p2 = multiprocessing.Process(target = receiver, args=(parent_conn,))
    p1.start()
    p2.start()
    p1.join()
    p2.join()

避免死锁

  1. 死锁原因:死锁通常发生在多个线程或进程相互等待对方释放资源的情况下。例如,线程A持有资源1并等待资源2,而线程B持有资源2并等待资源1。
  2. 避免方法
    • 按顺序获取锁:确保所有线程或进程以相同的顺序获取锁。例如,如果有锁lock1lock2,所有线程都先获取lock1,再获取lock2
    • 使用超时机制:在获取锁时设置超时时间,如果在超时时间内未能获取锁,则放弃获取并进行其他处理。例如,lock.acquire(timeout = 5)表示尝试获取锁,如果5秒内未获取到则返回False
    • 减少锁的持有时间:尽量缩短线程或进程持有锁的时间,尽快释放锁,让其他线程或进程有机会获取。