MST

星途 面试题库

面试题:高并发网络编程下多线程与多进程的优化策略

假设你正在开发一个高并发的后端网络服务,使用多线程或多进程进行编程。请详细说明你会采取哪些优化策略来避免线程/进程竞争、死锁等问题,提高系统的稳定性和性能,并举例说明如何在实际代码中实现这些策略。
19.5万 热度难度
后端开发网络编程

知识考点

AI 面试

面试题答案

一键面试

避免线程/进程竞争、死锁的优化策略

  1. 锁机制
    • 互斥锁(Mutex):用于保护共享资源,同一时间只有一个线程/进程能获取锁访问资源。例如在Python的threading模块中:
import threading

# 创建互斥锁
mutex = threading.Lock()
shared_resource = 0

def worker():
    global shared_resource
    mutex.acquire()
    try:
        shared_resource += 1
    finally:
        mutex.release()


threads = []
for _ in range(10):
    t = threading.Thread(target=worker)
    threads.append(t)
    t.start()

for t in threads:
    t.join()
print(shared_resource)
- **读写锁(Read - Write Lock)**:允许多个线程同时读共享资源,但写操作时需要独占。在C++中可以使用`std::shared_mutex`实现读写锁:
#include <iostream>
#include <thread>
#include <shared_mutex>

std::shared_mutex mtx;
int data = 0;

void read() {
    mtx.lock_shared();
    std::cout << "Read data: " << data << std::endl;
    mtx.unlock_shared();
}

void write() {
    mtx.lock();
    data++;
    std::cout << "Write data: " << data << std::endl;
    mtx.unlock();
}

int main() {
    std::thread t1(read);
    std::thread t2(write);
    std::thread t3(read);

    t1.join();
    t2.join();
    t3.join();

    return 0;
}
  1. 信号量(Semaphore):控制同时访问共享资源的线程/进程数量。在Java中使用Semaphore类:
import java.util.concurrent.Semaphore;

public class SemaphoreExample {
    private static final int MAX_THREADS = 3;
    private static final Semaphore semaphore = new Semaphore(MAX_THREADS);

    public static void main(String[] args) {
        for (int i = 0; i < 5; i++) {
            new Thread(() -> {
                try {
                    semaphore.acquire();
                    System.out.println(Thread.currentThread().getName() + " is accessing the resource.");
                    Thread.sleep(1000);
                    System.out.println(Thread.currentThread().getName() + " is leaving the resource.");
                    semaphore.release();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }).start();
        }
    }
}
  1. 资源分配图算法(预防死锁):通过对资源分配进行检查,确保系统不会进入死锁状态。例如银行家算法,通过预先判断资源分配是否安全来避免死锁。
  2. 避免嵌套锁:尽量避免一个线程/进程获取多个锁的嵌套情况。如果无法避免,确保所有线程/进程获取锁的顺序一致。例如:
lock1 = threading.Lock()
lock2 = threading.Lock()

# 所有线程都按照这种顺序获取锁
def thread_function1():
    lock1.acquire()
    try:
        lock2.acquire()
        try:
            # 操作共享资源
            pass
        finally:
            lock2.release()
    finally:
        lock1.release()


def thread_function2():
    lock1.acquire()
    try:
        lock2.acquire()
        try:
            # 操作共享资源
            pass
        finally:
            lock2.release()
    finally:
        lock1.release()


  1. 使用线程安全的数据结构:如Java中的ConcurrentHashMap,Python中的queue.Queue等。以Python的queue.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()


producer_thread = threading.Thread(target=producer)
consumer_thread = threading.Thread(target=consumer)

producer_thread.start()
consumer_thread.start()

producer_thread.join()
q.put(None)
consumer_thread.join()
  1. 线程/进程池:使用线程池或进程池可以减少线程/进程创建和销毁的开销,同时可以限制并发的数量,降低竞争风险。在Python中使用concurrent.futures模块的线程池:
import concurrent.futures


def task(x):
    return x * x


with concurrent.futures.ThreadPoolExecutor(max_workers=5) as executor:
    results = list(executor.map(task, range(10)))
print(results)

提高系统稳定性和性能的策略

  1. 减少共享资源:尽量减少线程/进程间共享的资源,降低竞争的可能性。如果可能,将数据进行分区,让每个线程/进程处理自己独立的数据部分。
  2. 优化算法和数据结构:选择合适的算法和数据结构可以提高效率,减少锁的持有时间。例如,使用哈希表代替线性查找的数据结构。
  3. 异步编程:对于I/O密集型任务,使用异步编程模型,如Python的asyncio库。这样线程/进程在等待I/O操作完成时不会阻塞,提高系统的并发性能。
import asyncio


async def io_bound_task():
    await asyncio.sleep(1)
    return "Task completed"


async def main():
    tasks = [io_bound_task() for _ in range(5)]
    results = await asyncio.gather(*tasks)
    print(results)


asyncio.run(main())
  1. 资源预分配:提前分配好所需的资源,避免在运行过程中频繁申请和释放资源导致的竞争。例如,在启动时分配好内存池。