java程序员怎么从Python小白变成Python大拿?(九)

文章9:并发编程与性能优化

目标

掌握并发编程的核心概念与工具,编写高效、可靠的Python程序。


一、多线程(Thread)与多进程(Process)的区别

1. 核心差异

特性 多线程(Thread) 多进程(Process)
资源共享 共享进程内存空间(受GIL限制) 独立内存空间,不共享数据
适用场景 I/O密集型任务(如网络请求、文件读写) CPU密集型任务(如计算、图像处理)
性能 受GIL限制,无法真正并行 利用多核CPU,实现并行
资源消耗 轻量级(创建/切换开销小) 重量级(内存占用大,进程间通信复杂)
稳定性 一个线程崩溃可能影响整个进程 进程间隔离,崩溃不影响其他进程

2. 全局解释器锁(GIL)的影响

  • GIL:CPython中,同一时间仅允许一个线程执行Python字节码。
  • 影响
  • 多线程在CPU密集型任务中无法提升性能(如循环计算)。
  • 多线程适合I/O操作,因等待I/O时会释放GIL。

3. 示例对比

scss 复制代码
# CPU密集型任务:计算斐波那契数列
import time
import threading
import multiprocessing

def fib(n):
    if n <= 1:
        return n
    return fib(n-1) + fib(n-2)

# 多线程(受GIL限制,性能差)
def thread_task():
    fib(35)

start = time.time()
threads = []
for _ in range(4):
    t = threading.Thread(target=thread_task)
    threads.append(t)
    t.start()
for t in threads:
    t.join()
print(f"Thread time: {time.time() - start:.2f}s")  # 约10秒(甚至更慢)

# 多进程(利用多核,性能提升)
def process_task():
    fib(35)

start = time.time()
processes = []
for _ in range(4):
    p = multiprocessing.Process(target=process_task)
    processes.append(p)
    p.start()
for p in processes:
    p.join()
print(f"Process time: {time.time() - start:.2f}s")  # 约2.5秒

二、使用​​concurrent.futures​​简化并发任务

1. 线程池与进程池

通过​​ThreadPoolExecutor​​​和​​ProcessPoolExecutor​​实现高效任务调度。

2. 示例:下载多个网页

python 复制代码
import concurrent.futures
import requests

urls = [
    "https://httpbin.org/delay/1",
    "https://httpbin.org/delay/2",
    "https://httpbin.org/delay/3"
]

def fetch_url(url):
    response = requests.get(url)
    return response.url, response.elapsed.total_seconds()

# 线程池(适合I/O密集型)
with concurrent.futures.ThreadPoolExecutor() as executor:
    results = list(executor.map(fetch_url, urls))
    print("Thread Pool Results:")
    for url, time_taken in results:
        print(f"{url} took {time_taken:.2f}s")

# 进程池(适合CPU密集型)
with concurrent.futures.ProcessPoolExecutor() as executor:
    results = list(executor.map(fetch_url, urls))  # 注意:进程间通信开销可能更大
    print("\nProcess Pool Results:")
    for url, time_taken in results:
        print(f"{url} took {time_taken:.2f}s")

3. 选择策略

  • 线程池:I/O操作(如网络请求、文件读写)。
  • 进程池:CPU计算(如数据处理、模型训练)。

三、Asyncio异步编程模型

1. 异步IO的核心概念

  • 事件循环:管理所有协程的执行。
  • 协程(Coroutine) :轻量级函数,通过​async def​定义,用​await​暂停/恢复。
  • 非阻塞:在等待I/O时,切换到其他任务,提升并发能力。

2. 示例:异步下载网页

python 复制代码
import asyncio
import aiohttp

urls = [
    "https://httpbin.org/delay/1",
    "https://httpbin.org/delay/2",
    "https://httpbin.org/delay/3"
]

async def fetch_url(session, url):
    async with session.get(url) as response:
        return url, response.elapsed.total_seconds()

async def main():
    async with aiohttp.ClientSession() as session:
        tasks = []
        for url in urls:
            tasks.append(fetch_url(session, url))
        results = await asyncio.gather(*tasks)
        for url, time_taken in results:
            print(f"{url} took {time_taken:.2f}s")

asyncio.run(main())

3. 优势场景

  • 高并发I/O:如Web服务器、实时数据处理。
  • 单线程高效:避免GIL限制,减少线程切换开销。

四、性能分析工具

1. ​​cProfile​​:分析代码性能瓶颈

python 复制代码
import cProfile

def compute_heavy():
    return sum(i**2 for i in range(1000000))

cProfile.run('compute_heavy()')

输出示例:

bash 复制代码
2 function calls in 0.002 seconds

2. ​​timeit​​:精确测量代码片段

python 复制代码
import timeit

print(timeit.timeit('sum(range(1000))', number=1000))
# 输出:例如:0.007秒

3. 优化步骤

  1. 识别瓶颈 :用​cProfile​定位耗时函数。
  2. 替换算法/数据结构:如用NumPy替代纯Python循环。
  3. 并行化:将CPU任务转为多进程,I/O任务用异步或线程池。

五、综合案例:Web爬虫优化

1. 同步版(低效)

python 复制代码
import requests

urls = ["https://example.com/page" + str(i) for i in range(10)]

def sync_crawl():
    for url in urls:
        response = requests.get(url)
        print(f"Downloaded {url} in {response.elapsed.total_seconds():.2f}s")
sync_crawl()

2. 异步版(高效)

python 复制代码
import asyncio
import aiohttp

async def async_crawl():
    async with aiohttp.ClientSession() as session:
        tasks = []
        for url in urls:
            tasks.append(session.get(url))
        responses = await asyncio.gather(*tasks)
        for resp in responses:
            print(f"Downloaded {resp.url} in {resp.elapsed.total_seconds():.2f}s")

asyncio.run(async_crawl())

总结

通过本文,你已掌握:

  • 多线程/多进程:选择合适场景,绕过GIL限制。
  • concurrent.futures:高效管理线程/进程池。
  • Asyncio:用异步IO处理高并发I/O任务。
  • 性能分析工具:定位瓶颈,针对性优化。

根据任务类型选择方案:

  • CPU密集 → 多进程。
  • I/O密集 → 多线程或异步IO。
  • 高并发网络 → Asyncio。

现在,你可以用这些工具优化你的Python程序,提升性能与可靠性!

相关推荐
夜白宋31 分钟前
【word多文档docx合并】
java·word
@yanyu6661 小时前
idea中配置tomcat
java·mysql·tomcat
2501_916766541 小时前
【项目部署】JavaWeb、MavenJavaWeb项目部署至 Tomcat 的实现方式
java·tomcat
RoboWizard1 小时前
扩容刚需 金士顿新款Canvas Plus存储卡
java·spring·缓存·电脑·金士顿
lang201509281 小时前
Spring Boot 入门:5分钟搭建Hello World
java·spring boot·后端
失散131 小时前
分布式专题——47 ElasticSearch搜索相关性详解
java·分布式·elasticsearch·架构
serve the people2 小时前
LangChain 表达式语言核心组合:Prompt + LLM + OutputParser
java·langchain·prompt
想ai抽2 小时前
深入starrocks-多列联合统计一致性探查与策略(YY一下)
java·数据库·数据仓库
武子康2 小时前
Java-152 深入浅出 MongoDB 索引详解 从 MongoDB B-树 到 MySQL B+树 索引机制、数据结构与应用场景的全面对比分析
java·开发语言·数据库·sql·mongodb·性能优化·nosql
杰克尼2 小时前
JavaWeb_p165部门管理
java·开发语言·前端