/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */
#content_views .toc,
/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */
#content_views.markdown_views > p:empty:has(+ .toc),
#content_views.markdown_views > .toc + p:empty,
/* 富文本旧版目录标记 */
#content_views.htmledit_views #main-toc,
#content_views.htmledit_views #hr-toc,
#content_views.htmledit_views p[id*=\”-toc\”] {
display: none !important;
}
/* 目录去掉后,紧跟的首个标题不再多出一块上边距 */
#content_views.markdown_views > .toc + h1,
#content_views.markdown_views > .toc + h2,
#content_views.markdown_views > .toc + h3,
#content_views.markdown_views > .toc + h4,
#content_views.markdown_views > .toc + p:empty + h1,
#content_views.markdown_views > .toc + p:empty + h2,
#content_views.markdown_views > .toc + p:empty + h3,
#content_views.markdown_views > .toc + p:empty + h4 {
margin-top: 0 !important;
}
场景开头:你要给 200 个接口逐个发请求拉数据。串行跑完要 98 秒,产品经理在群里问\”怎么这么慢\”。如果你正在做批量抓取、批量推送、批量查库这类 I/O 密集型活,这篇就是写给你的——用三套代码把 98 秒压到 4 秒以内,并讲清什么场景该用哪个。
一、为什么串行慢,并发能快
Python 的慢,九成不是 CPU 慢,而是你在等。一次 requests.get 里有 90% 的时间花在网络往返上,CPU 在那段时间是空闲的。串行代码的问题在于:发完一个请求、收到响应、再发下一个,把本可以重叠的等待时间硬生生串成了队列。
并发的本质,就是让\”等待\”这件事尽量重叠:A 在等网络时,B 已经发出去了。但 Python 有三种并发模型,选错比不选还糟:
- 多线程(threading / ThreadPoolExecutor):靠操作系统调度多个线程,I/O 等待时释放 GIL,所以适合 I/O 密集型;但受 GIL 限制,干不了 CPU 密集型并行。
- 协程(asyncio):单线程事件循环,在 await 点主动让出控制权,几 KB 一个协程,能轻松扛上万并发连接,内存密度远高于线程。
- 多进程(multiprocessing):绕过 GIL,真正并行,但进程间通信贵,只该留给 CPU 密集型。
记住一句话:I/O 多连接用 asyncio,I/O 少量连接用线程池,CPU 密集用进程池,千万别用线程跑 CPU 活。
二、基准测试:三套代码直接跑
下面这套脚本把同一个\”20 个延迟接口\”分别用串行、线程池、asyncio 跑一遍,并打印耗时。依赖:pip install requests aiohttp。
\”\”\”
并发请求基准测试:串行 / 线程池 / asyncio 三方案对比
依赖:pip install requests aiohttp
运行:python concurrency_bench.py
\”\”\”
import time
import asyncio
import requests
from concurrent.futures import ThreadPoolExecutor, as_completed
# 用 httpbin 的延迟接口模拟一次 I/O 等待(每个约 0.1s)
URLS = [f\”https://ht
网硕互联帮助中心


评论前必须登录!
注册