Python并发编程实操教程:多线程/多进程/异步全解析

并发编程是Python提升程序执行效率的核心技能,不管是处理IO密集型任务(如网络请求、文件读写),还是CPU密集型任务(如数据计算、矩阵运算),掌握并发都能让程序"跑更快"。

一、核心认知:并发vs并行(新手必懂)

很多人容易混淆"并发"和"并行",先理清核心区别:

概念 核心定义 适用场景
并发(Concurrency) 多个任务交替执行(同一时间只有一个任务在跑),看似"同时进行" IO密集型任务(等待时间长)
并行(Parallelism) 多个任务真正同时执行(利用多核CPU),物理上的"同时进行" CPU密集型任务(计算量大)

Python实现并发/并行的三大核心方式:

  • 多线程(threading):并发,适合IO密集型任务;
  • 多进程(multiprocessing):并行,适合CPU密集型任务;
  • 异步IO(asyncio):单线程并发,极致优化IO密集型任务。

二、多线程:IO密集型任务首选(threading模块)

1. 核心原理

线程是进程内的执行单元,共享进程内存空间,切换开销小。Python的threading模块实现多线程,但受GIL(全局解释器锁)限制,同一时间只有一个线程执行Python字节码------因此多线程仅对"等待型"IO任务有效(如网络请求、文件读写)。

2. 基础用法:创建和启动线程

python 复制代码
import threading
import time

 定义线程执行的函数(模拟IO任务:网络请求)
def fetch_url(url, delay):
    print(f"线程{threading.current_thread().name}:开始请求{url}")
    time.sleep(delay)   模拟网络等待
    print(f"线程{threading.current_thread().name}:{url}请求完成")

if __name__ == "__main__":
    start_time = time.time()
    
     创建2个线程
    t1 = threading.Thread(target=fetch_url, args=("https://baidu.com", 2), name="t1")
    t2 = threading.Thread(target=fetch_url, args=("https://github.com", 2), name="t2")
    
     启动线程
    t1.start()
    t2.start()
    
     等待线程结束(主进程阻塞)
    t1.join()
    t2.join()
    
    print(f"总耗时:{time.time() - start_time:.2f}秒")

执行结果

arduino 复制代码
线程t1:开始请求https://baidu.com
线程t2:开始请求https://github.com
线程t1:https://baidu.com请求完成
线程t2:https://github.com请求完成
总耗时:2.01秒

(单线程执行需4秒,多线程仅需2秒,体现IO任务并发优势)

3. 实用进阶:线程池(ThreadPoolExecutor)

手动创建大量线程会导致资源耗尽,concurrent.futures.ThreadPoolExecutor(高层封装)可限制线程数量、复用线程,是批量IO任务的首选。

python 复制代码
from concurrent.futures import ThreadPoolExecutor
import time

def fetch_url(url, delay):
    print(f"开始请求{url}")
    time.sleep(delay)
    return f"{url}请求完成"

if __name__ == "__main__":
    start_time = time.time()
    urls = [
        ("https://baidu.com", 2),
        ("https://github.com", 2),
        ("https://python.org", 2)
    ]
    
     创建线程池(最多3个线程)
    with ThreadPoolExecutor(max_workers=3) as executor:
         批量提交任务
        results = [executor.submit(fetch_url, url, delay) for url, delay in urls]
         获取结果
        for res in results:
            print(res.result())
    
    print(f"总耗时:{time.time() - start_time:.2f}秒")

执行结果:总耗时≈2秒(3个IO任务并发执行)。

4. 适用场景

  • 网络请求(爬虫、接口调用)、文件读写、数据库操作等IO密集型任务;
  • 任务切换频繁、等待时间长的场景;
  • 需共享内存数据(线程共享进程内存,无需额外通信)。

三、多进程:CPU密集型任务首选(multiprocessing模块)

1. 核心原理

进程是独立的执行单元,每个进程有自己的GIL,可利用多核CPU并行执行。multiprocessing模块突破GIL限制,是CPU密集型任务的最优解,但进程切换开销比线程大。

2. 基础用法:创建和启动进程

python 复制代码
import multiprocessing
import time

 定义进程执行的函数(模拟CPU任务:计算)
def calculate_square(num):
    print(f"进程{multiprocessing.current_process().pid}:计算{num}的平方")
    time.sleep(1)   模拟计算耗时
    return num * num

if __name__ == "__main__":
    start_time = time.time()
    
     创建2个进程
    p1 = multiprocessing.Process(target=calculate_square, args=(10,))
    p2 = multiprocessing.Process(target=calculate_square, args=(20,))
    
    p1.start()
    p2.start()
    p1.join()
    p2.join()
    
    print(f"总耗时:{time.time() - start_time:.2f}秒")

执行结果:总耗时≈1秒(2个CPU任务并行执行)。

3. 实用进阶:进程池(Pool/ProcessPoolExecutor)

批量CPU任务推荐用进程池,避免手动创建大量进程:

python 复制代码
from concurrent.futures import ProcessPoolExecutor
import time

def calculate_square(num):
    time.sleep(1)
    return num * num

if __name__ == "__main__":
    start_time = time.time()
    nums = [1,2,3,4,5,6,7,8]
    
     创建进程池(适配CPU核心数)
    with ProcessPoolExecutor() as executor:
        results = executor.map(calculate_square, nums)
    
    print("计算结果:", list(results))
    print(f"总耗时:{time.time() - start_time:.2f}秒")

执行结果:8个任务,4核CPU并行执行,总耗时≈2秒(单进程需8秒)。

4. 适用场景

  • 数据计算、矩阵运算、图片处理、密码破解等CPU密集型任务;
  • 需充分利用多核CPU的场景;
  • 任务间无频繁数据共享(进程内存隔离,通信开销大)。

四、异步IO:极致IO密集型优化(asyncio模块)

1. 核心原理

异步IO是单线程内的"非阻塞"并发,通过事件循环(Event Loop)管理任务,当一个任务等待IO时,自动切换到其他任务执行------比多线程更轻量(无线程切换开销),是IO密集型任务的极致优化方案。

2. 核心概念(新手必记)

  • 协程(Coroutine) :异步执行的函数,用async def定义;
  • 事件循环(Event Loop):协程的调度器,负责管理任务执行;
  • await:标记IO等待点,触发任务切换;
  • Task:封装协程,加入事件循环执行。

3. 基础用法:简单异步任务

python 复制代码
import asyncio
import time

 定义异步函数(协程)
async def fetch_url(url, delay):
    print(f"开始请求{url}")
    await asyncio.sleep(delay)   异步等待(非阻塞)
    print(f"{url}请求完成")
    return url

async def main():
    start_time = time.time()
     创建协程任务
    task1 = asyncio.create_task(fetch_url("https://baidu.com", 2))
    task2 = asyncio.create_task(fetch_url("https://github.com", 2))
     等待所有任务完成
    await task1
    await task2
    print(f"总耗时:{time.time() - start_time:.2f}秒")

 运行事件循环
if __name__ == "__main__":
    asyncio.run(main())

执行结果:总耗时≈2秒(单线程内2个IO任务并发)。

4. 实用进阶:批量异步任务

python 复制代码
import asyncio
import time

async def fetch_url(url, delay):
    await asyncio.sleep(delay)
    return f"{url}请求完成"

async def main():
    start_time = time.time()
    urls = [
        ("https://baidu.com", 2),
        ("https://github.com", 2),
        ("https://python.org", 2)
    ]
     批量创建任务
    tasks = [asyncio.create_task(fetch_url(url, delay)) for url, delay in urls]
     等待所有任务完成
    results = await asyncio.gather(*tasks)
    for res in results:
        print(res)
    print(f"总耗时:{time.time() - start_time:.2f}秒")

if __name__ == "__main__":
    asyncio.run(main())

执行结果:3个IO任务单线程并发,总耗时≈2秒。

5. 适用场景

  • 高并发IO任务(如百万级网络请求、高并发接口服务);
  • 追求极致性能的IO密集型场景;
  • 单线程内的非阻塞任务(如异步Web框架FastAPI)。

五、三大并发模式对比(选型核心)

特性 多线程(threading) 多进程(multiprocessing) 异步IO(asyncio)
核心优势 轻量、共享内存 多核并行、突破GIL 极致轻量、无切换开销
核心劣势 受GIL限制、线程安全 内存隔离、通信开销大 代码改造成本高、仅支持异步库
适用任务 IO密集型 CPU密集型 高并发IO密集型
资源开销 极低
代码复杂度

六、实战案例:不同场景的并发选型

场景1:爬虫(IO密集型)

  • 推荐方案:异步IO(asyncio + aiohttp)
python 复制代码
import asyncio
import aiohttp   异步HTTP库

async def fetch(url):
    async with aiohttp.ClientSession() as session:
        async with session.get(url) as response:
            return f"{url}:状态码{response.status}"

async def main():
    urls = [
        "https://baidu.com",
        "https://github.com",
        "https://python.org"
    ]
    tasks = [asyncio.create_task(fetch(url)) for url in urls]
    results = await asyncio.gather(*tasks)
    for res in results:
        print(res)

if __name__ == "__main__":
    asyncio.run(main())

场景2:数据计算(CPU密集型)

  • 推荐方案:多进程(ProcessPoolExecutor)
python 复制代码
from concurrent.futures import ProcessPoolExecutor
import numpy as np

def matrix_calculate(matrix):
     矩阵乘法(CPU密集)
    return np.dot(matrix, matrix)

if __name__ == "__main__":
     生成10个随机矩阵
    matrices = [np.random.rand(1000, 1000) for _ in range(10)]
    with ProcessPoolExecutor() as executor:
        results = executor.map(matrix_calculate, matrices)
    print("矩阵计算完成,共处理", len(list(results)), "个矩阵")

场景3:文件批量处理(IO+轻量计算)

  • 推荐方案:多线程(ThreadPoolExecutor)
python 复制代码
from concurrent.futures import ThreadPoolExecutor
import os

def process_file(filepath):
     读取文件+简单处理(IO+轻量计算)
    with open(filepath, "r", encoding="utf-8") as f:
        content = f.read()
     统计字符数
    return f"{filepath}:字符数{len(content)}"

if __name__ == "__main__":
     获取当前目录下的所有txt文件
    files = [f for f in os.listdir() if f.endswith(".txt")]
    with ThreadPoolExecutor(max_workers=5) as executor:
        results = executor.map(process_file, files)
    for res in results:
        print(res)

七、避坑指南:新手常见错误

1. 坑1:用多线程处理CPU密集型任务

  • 现象:程序运行速度比单线程还慢;
  • 原因:GIL限制+线程切换开销;
  • 解决方案:改用多进程。

2. 坑2:Windows系统多进程未加if __name__ == "__main__"

  • 现象:报错RuntimeError: An attempt has been made to start a new process
  • 原因:Windows创建进程时重新导入脚本,递归创建进程;
  • 解决方案:所有创建进程的代码放在if __name__ == "__main__"下。

3. 坑3:异步代码中调用同步阻塞函数

  • 现象:异步任务失去并发优势;
  • 原因:time.sleep()requests.get()等同步函数会阻塞事件循环;
  • 解决方案:改用异步库(如asyncio.sleep()aiohttp)。

4. 坑4:过度并发导致资源耗尽

  • 现象:程序崩溃、服务器连接被拒绝;
  • 原因:线程/进程/异步任务数量过多;
  • 解决方案:限制并发数(如线程池max_workers、异步任务限流)。
相关推荐
shangjian0071 小时前
Python基础-闭包和装饰器
开发语言·python
三维空间1 小时前
如何在Python多进程中避免死锁问题?
python
dhdjjsjs1 小时前
Day30 Python Study
开发语言·前端·python
Eric.Lee20212 小时前
mujoco构建无物理约束的几何体运动
python·物理引擎·mujoco·物理模型仿真
wadesir2 小时前
用Python实现ggplot2风格绘图(零基础入门Seaborn与Matplotlib美化技巧)
开发语言·python·matplotlib
ㄣ知冷煖★2 小时前
基于openEuler操作系统的图神经网络应用开发:以Cora数据集节点分类为例的研究与实践
python
祝余Eleanor2 小时前
Day32 深入理解SHAP图
人工智能·python·机器学习
int WINGsssss3 小时前
【无标题】
pytorch·分布式·python
q_30238195563 小时前
Python实现基于多模态知识图谱的中医智能辅助诊疗系统:迈向智慧中医的新篇章
开发语言·python·知识图谱