Python 中的并发

Python 中的并发编程主要包含多线程、多进程和异步 IO三大核心。
多线程适用于 IO 密集型任务(如网络请求、文件读写),多进程适用于 CPU 密集型任务,异步 IO 则是单线程下的高效并发模式

1.多线程高级用法核心模块

   Python 中多线程的核心模块有两个:
   threading:基础线程模块(Python 内置)
   concurrent.futures.ThreadPoolExecutor高级线程池(推荐,简化线程管理)
   (1)线程池(ThreadPoolExecutor):批量任务并发
       线程池可以避免频繁创建 / 销毁线程的开销,是生产环境中最常用的多线程方式。
       示例:批量请求接口(IO 密集型)

import requests
from concurrent.futures import ThreadPoolExecutor, as_completed
import time

# 待请求的 URL 列表
URLS = [
    "https://www.baidu.com",
    "https://www.github.com",
    "https://www.python.org",
    "https://www.zhihu.com",
    "https://www.bilibili.com"
]

def fetch_url(url):
    """请求单个 URL 并返回结果"""
    start = time.time()
    try:
        response = requests.get(url, timeout=5)
        return {
            "url": url,
            "status": response.status_code,
            "time": round(time.time() - start, 2)
        }
    except Exception as e:
        return {
            "url": url,
            "status": "failed",
            "error": str(e),
            "time": round(time.time() - start, 2)
        }

def main():
    start_total = time.time()
    
    # 创建线程池(max_workers 控制并发数,建议设为 CPU 核心数 * 5 ~ 10,IO 密集型可更大)
    with ThreadPoolExecutor(max_workers=5) as executor:
        # 方式1:提交任务并获取结果(按完成顺序)
        future_to_url = {executor.submit(fetch_url, url): url for url in URLS}
        
        for future in as_completed(future_to_url):
            result = future.result()
            print(f"URL: {result['url']} | 状态: {result['status']} | 耗时: {result['time']}s")
    
    print(f"\n总耗时: {round(time.time() - start_total, 2)}s")

if __name__ == "__main__":
    main()

       关键特性:
       with 语句自动管理线程池生命周期(无需手动关闭)
       s_completed 按任务完成顺序获取结果(而非提交顺序)
       submit() 返回 Future 对象,可通过 result() 获取结果(阻塞)、done() 判断是否完成
       map() 方法可批量处理迭代器(按提交顺序返回结果)

with ThreadPoolExecutor(max_workers=5) as executor:
    results = executor.map(fetch_url, URLS)
    for result in results:
        print(result)

 

2.多线程的局限性:GIL 锁

    Python 的 全局解释器锁(GIL) 导致同一时刻只有一个线程执行 Python 字节码,因此:
   多线程无法加速 CPU 密集型任务(如计算、循环)
   多线程仅适用于 IO 密集型任务(线程等待 IO 时释放 GIL,其他线程可执行)
   解决方案:
   CPU 密集型任务用 multiprocessing(多进程,绕过 GIL)
   高并发 IO 用 asyncio(异步 IO,单线程非阻塞)

3.进阶:多线程 + 异步混合使用

对于复杂场景(如 IO 密集型任务中包含少量 CPU 计算),可结合线程池和异步 IO:
import asyncio from concurrent.futures import ThreadPoolExecutor import time # CPU 密集型函数 def cpu_bound_task(n): return sum(i * i for i in range(n)) # 异步函数 async def main(): executor = ThreadPoolExecutor(max_workers=4) loop = asyncio.get_running_loop() # 在线程池中执行 CPU 密集型任务(不阻塞事件循环) tasks = [ loop.run_in_executor(executor, cpu_bound_task, 10000000), loop.run_in_executor(executor, cpu_bound_task, 10000000), loop.run_in_executor(executor, cpu_bound_task, 10000000) ] results = await asyncio.gather(*tasks) print(f"结果: {results}") if __name__ == "__main__": start = time.time() asyncio.run(main()) print(f"总耗时: {time.time() - start:.2f}s")

4.生产环境最佳实践

    (1)线程数设置
        IO 密集型:max_workers = CPU核心数 * 5 ~ 10(如 8 核 CPU 设 50)
        避免设置过大(线程切换开销增加)
    (2)异常处理
        线程内捕获所有异常(避免单个线程崩溃导致整体异常)
        使用 future.exception() 获取线程池任务的异常
    (3)资源释放
        用 with 语句管理线程池 / 锁(自动释放资源)
        避免全局锁(缩小锁的作用域)
    (4)监控与调试
        使用 threading.enumerate() 查看所有活跃线程
        避免死锁(如锁的顺序一致、设置超时)
    (5)总结
        多线程核心场景:IO 密集型任务(网络请求、文件读写)
        高级用法:线程池、线程同步、生产者 - 消费者模型
        局限性:GIL 导致无法加速 CPU 密集型任务(改用多进程 / 异步)
        生产推荐:优先使用 ThreadPoolExecutor 而非手动管理线程,结合队列 / 锁保证线程安全。

posted on 2025-12-23 22:16  枫飘过的天1  阅读(4)  评论(0)    收藏  举报