第4章 Python并发与多线程/多进程:高频问题、回答框架、公司侧重点
本章聚焦面试中最常出现的并发场景:何时使用线程 vs 进程、GIL的影响、以及如何设计线程安全/进程安全的代码。大厂面试官常通过这个问题考察候选人对底层机制的理解深度和工程选型能力。下方回答框架图可作为解题导航。
面试问答卡片
Q1:Python多线程和多进程有什么区别?各自适用什么场景?
| 面试官考察点 | 是否真正理解GIL的本质,能否根据任务类型选择并发模型,对操作系统调度的基本认知。 |
| 回答框架 | 1) 指出GIL限制多线程CPU并行;2) 多进程有独立GIL适合CPU密集;3) 多线程轻量适合IO密集;4) 补充协程作为现代替代方案。 |
| 简短示例回答 | 多线程共享内存,但受GIL影响,仅适合IO密集型任务(如网络请求、文件读写)。多进程有独立GIL和内存空间,适合CPU密集型(如计算)。协程基于事件循环,可兼顾部分场景。例如爬虫用ThreadPoolExecutor,图像处理用ProcessPoolExecutor。 |
| 可能追问 | GIL为什么被设计?如何绕过GIL?multiprocessing和concurrent.futures的区别? |
| 避坑提醒 | 不要只说“多线程没用”,面试官希望看到你清楚说“什么时候用”。避免把协程和线程混为一谈。 |
Q2:如何避免线程/进程间的数据竞争?请列举至少两种同步机制。
| 面试官考察点 | 是否掌握常见锁、信号量、队列等同步原语,能否处理死锁和性能问题。 |
| 回答框架 | 1) 区分竞争根源;2) 介绍Lock/Rlock;3) 介绍Semaphore和Condition;4) 推荐使用queue.Queue进行线程安全通信;5) 提到multiprocessing.Manager用于进程共享。 |
| 简短示例回答 | 使用threading.Lock保护临界区,或用queue.Queue自动加锁。进程间用multiprocessing.Manager的dict/list或Pipe。例如计数器更新:with lock: count += 1。避免死锁:统一获取锁的顺序或使用超时锁lock.acquire(timeout=5)。 |
| 可能追问 | 读写锁如何实现?与乐观锁的区别?Python有内置的读写锁吗? |
| 避坑提醒 | 不要背诵锁API,要讲使用场景。避免说“加锁就安全了”,讲清死锁、饥饿、性能退化等问题。 |
Q3:Python并发编程中,如何选择ThreadPoolExecutor、ProcessPoolExecutor和asyncio?
| 面试官考察点 | 是否理解三个模型的设计哲学与性能边界,能否在生产中做出合理选型。 |
| 回答框架 | 1) ThreadPoolExecutor: IO密集、任务数较多;2) ProcessPoolExecutor: CPU密集、任务独立;3) asyncio: 高并发IO、单线程事件驱动;4) 实际可组合使用,如run_in_executor。 |
| 简短示例回答 | Web API调用用asyncio(aiohttp);CPU计算用ProcessPoolExecutor(multiprocessing);混合场景:asyncio中调用loop.run_in_executor把阻塞任务扔进线程池。例如异步Web服务中,数据库查询走线程池,计算走进程池。 |
| 可能追问 | asyncio中的协程是真正的并发吗?如何调试并发问题?线程池大小如何设置为最优? |
| 避坑提醒 | 不要盲目使用asyncio面对CPU任务;注意ProcessPoolExecutor的序列化开销;避免默认线程池数量过大导致资源耗尽。 |
项目案例:高并发爬虫调度系统
| 项目名称 | 分布式通用爬虫调度引擎 |
| 业务背景 | 需对1000+站点进行定时抓取,要求低延迟、高吞吐,支持动态扩容。 |
| 规模指标 | 单机并发爬取300+请求/秒,总任务数日均500万;峰值QPS 1500。 |
| 技术栈 | Python 3.10, asyncio + aiohttp, multiprocessing.Pool, Redis任务队列, Prometheus监控。 |
| 核心难点 | 1) IO密集与CPU计算混杂(解析、去重);2) 避免线程与协程混用时的上下文切换开销;3) 动态调整并发度防止封IP。 |
| 面试高频追问 | 为什么选择asyncio+进程池组合?如何监控协程运行状态?多进程间如何共享去重缓存? |
| 可迁移回答话术 | “针对混合负载,我采用分层并发模型:asyncio处理网络IO,通过loop.run_in_executor将CPU密集的解析任务派发给进程池,避免阻塞事件循环。同时使用Redis有序集合实现跨进程URL去重,配合Semaphore控制并发窗口。这种模式在后续的实时数据清洗链路中也复用了。” |
💡 本章侧重点提示 大厂面试时,字节跳动偏好考察GIL底层实现与asyncio原理;腾讯常结合网络服务问并发模型选型;阿里则关注高并发下的稳定性与资源控制。建议重点准备“为什么GIL不删除”和“线程池调优”两个方向。
📌 复习建议 画一张思维导图:左侧是三种并发模型,中间是GIL/锁/队列,右侧对应典型项目场景。每复习一个知识点,在导图上标注你的项目案例或常见Bug。