什么是异步?Python 开发者必懂的 20 个“黑话”术语
1. 引言“异步”这个词在编程圈里几乎天天都能听到但很多初学者甚至有一定经验的开发者第一次接触时都会觉得它很抽象、很难理解。更让人头疼的是围绕“异步”还有一大串听起来就很吓人的术语协程、事件循环、回调地狱、非阻塞 I/O、Future、Promise、asyncio、await、async…… 这些词单独拎出来可能还能猜个大概但放在一起就让人彻底懵了。这篇文章的目标很简单用最直白的大白话把这些“黑话”一个一个拆解清楚。如果你是 Python 开发者或者正在学习 Python 异步编程这篇文章就是为你准备的。2. 什么是异步先搞懂核心思想2.1 一个生活化的比喻去奶茶店点单想象你去一家奶茶店同步Synchronous你点完单就站在柜台前一动不动死死盯着店员做奶茶。店员做一杯你等一杯。在这期间你什么别的事都干不了。这就是“同步”——你必须等一件事做完才能做下一件事。异步Asynchronous你点完单拿了个号然后就去旁边刷手机、回消息、甚至去隔壁买个面包。等奶茶做好了店员会叫号“138 号您的奶茶好了”你听到叫号再过去取。这就是“异步”——你不用干等可以先去干别的事等结果准备好了再回来处理。2.2 编程里的异步在程序里异步的核心就是当一个任务需要等待比如等待网络响应、等待磁盘读写、等待数据库查询时程序不傻等而是先去执行其他任务等那个慢任务完成了再回来继续处理它。这就像 CPU 在说“你慢慢等我先去干点别的活别浪费我的时间。”3. 异步相关的核心术语Python 开发者必知下面这些术语是你在学习 Python 异步编程时一定会遇到的。我把它们分成几个等级从最基础到进阶逐个击破。3.1 基础概念篇1. 阻塞Blocking大白话程序执行到某一步卡住了必须等这一步完成才能继续往下走。Python 例子time.sleep(5)就是典型的阻塞操作。程序会在这里停 5 秒什么事都不干。为什么不好浪费 CPU 资源程序响应慢。2. 非阻塞Non-blocking大白话程序执行到某一步发现需要等待但它不卡住而是立刻返回一个“还没好”的信号然后继续干别的事。Python 例子使用socket.setblocking(False)设置非阻塞套接字调用recv()时如果没有数据会立刻抛出一个异常而不是一直等。3. 同步Synchronous大白话按顺序执行做完一件再做下一件。你调用一个函数必须等它返回结果才能执行下一行代码。Python 例子普通的函数调用result func()在func()执行完之前后面的代码不会运行。4. 异步Asynchronous大白话你调用一个函数它立刻返回一个“凭证”比如 Future 对象告诉你“我正在处理好了通知你”。然后你的程序可以继续往下跑等结果准备好了再回来取。Python 例子asyncio库中的await关键字就是用来处理异步操作的。3.2 Python 异步编程核心篇5. 事件循环Event Loop大白话事件循环就像一个“超级调度员”。它不停地问“谁准备好了谁可以继续执行了” 它负责管理所有异步任务当一个任务在等待时它就把 CPU 让给另一个可以执行的任务。Python 例子asyncio.run(main())会创建一个事件循环然后运行main()这个协程。6. 协程Coroutine大白话协程是一种特殊的函数它可以“暂停”和“恢复”。你调用它时它不会立刻执行完而是返回一个协程对象。你需要用await来让它真正开始执行并且在遇到await时它可以暂停把控制权交还给事件循环。Python 例子asyncdefmy_coroutine():print(开始执行)awaitasyncio.sleep(1)# 暂停让出控制权print(1秒后继续执行)注意async def定义的就是一个协程函数。7. await大白话await是 Python 里的一个关键字意思是“等待一个异步操作完成”。但它不是傻等而是说“事件循环我现在要等这个操作你先去干别的活等它好了再叫我。”Python 例子data await fetch_data()表示“我去拿数据了你先忙别的数据到了再回来处理”。8. async / await 关键字大白话async用来声明一个函数是异步的即协程await用来等待一个异步操作的结果。它们俩是 Python 异步编程的基石。Python 例子asyncdefmain():print(Hello)awaitasyncio.sleep(1)print(World)9. asyncio大白话Python 标准库中用于编写异步代码的库。它提供了事件循环、协程、任务、Future 等所有你需要的东西。Python 例子asyncio.run()、asyncio.sleep()、asyncio.gather()都是 asyncio 提供的。10. 任务Task大白话任务是对协程的一层包装。你可以把任务理解为“一个正在被事件循环管理的协程”。事件循环会调度任务的执行。Python 例子taskasyncio.create_task(my_coroutine())# 现在 my_coroutine 会被事件循环调度执行awaittask11. Future大白话Future 是一个“未来结果”的占位符。当你发起一个异步操作时它立刻返回一个 Future 对象这个对象将来会包含操作的结果。你可以把它想象成一张“取餐小票”凭票将来取餐。Python 例子在底层await一个协程时Python 会自动把它包装成一个 Future。你一般不会直接操作 Future但理解它对理解异步机制很有帮助。3.3 进阶与相关概念篇12. 回调Callback大白话你告诉程序“等你做完这件事就调用这个函数。” 这个函数就是回调函数。Python 例子defdone_callback(future):print(f任务完成结果是{future.result()})taskasyncio.create_task(my_coroutine())task.add_done_callback(done_callback)缺点回调嵌套多了会形成“回调地狱”代码难以阅读和维护。13. 回调地狱Callback Hell大白话回调函数里再套回调函数再套回调函数……代码层层缩进像一座金字塔非常难看逻辑也混乱。Python 例子在旧版的异步库如 Twisted中很常见。async/await的出现就是为了解决回调地狱。14. 并发Concurrency大白话并发是指“看起来像是同时执行”。在单核 CPU 上通过快速切换任务让多个任务交替执行给人一种“同时进行”的错觉。异步就是实现并发的一种方式。类比一个人同时做几件事比如一边烧水一边切菜但同一时间只能做一件只是切换得很快。15. 并行Parallelism大白话并行是指“真正的同时执行”。这需要多核 CPU每个核心独立执行一个任务。类比两个人一个人烧水一个人切菜同时进行。区别并发是逻辑上的同时并行是物理上的同时。异步编程主要解决的是并发问题而不是并行问题。16. 多线程Multithreading大白话一个进程里开多个线程每个线程可以独立执行任务。Python 的多线程由于 GIL全局解释器锁的存在在 CPU 密集型任务上无法实现真正的并行但在 I/O 密集型任务上仍然有用。与异步的关系异步和多线程都可以实现并发。异步是单线程的在事件循环中而多线程是多线程的。异步的切换开销比线程切换小得多。17. 多进程Multiprocessing大白话开多个进程每个进程有自己独立的 Python 解释器和内存空间。可以绕过 GIL实现真正的并行CPU 密集型任务。与异步的关系多进程适合 CPU 密集型任务异步适合 I/O 密集型任务。18. I/O 密集型 vs CPU 密集型I/O 密集型程序大部分时间在等待输入/输出如网络请求、文件读写、数据库查询。异步编程最适合这种场景。CPU 密集型程序大部分时间在计算如视频编码、数学计算、机器学习训练。多进程或 C 扩展更适合这种场景。19. 生成器Generator与协程的前世今生大白话在 Python 3.5 引入async/await之前协程是通过生成器yield来实现的。生成器可以暂停和恢复和协程很像。所以你会看到一些老代码用asyncio.coroutine和yield from来实现异步。Python 例子# 旧式协程Python 3.4 及之前asyncio.coroutinedefold_style_coro():yieldfromasyncio.sleep(1)现在推荐使用async/await生成器协程已经过时。20. aiohttp / aiofiles / asyncpg大白话这些都是基于asyncio的第三方库分别用于异步 HTTP 请求、异步文件读写、异步 PostgreSQL 数据库操作。它们是 Python 异步生态的重要组成部分。例子importaiohttpasyncdeffetch(url):asyncwithaiohttp.ClientSession()assession:asyncwithsession.get(url)asresponse:returnawaitresponse.text()4. 总结术语一句话大白话异步不等先干别的好了叫我同步必须等做完一件再做下一件阻塞卡住了啥也干不了非阻塞不等立刻返回“还没好”事件循环超级调度员谁准备好了就执行谁协程可以暂停和恢复的特殊函数await等异步操作完成但不傻等Task被事件循环管理的协程Future未来结果的占位符取餐小票回调做完事后调用的函数并发看起来同时做单核快速切换并行真正同时做多核I/O 密集型大部分时间在等适合异步CPU 密集型大部分时间在算适合多进程5. 下一步学习建议动手写打开 Python 终端用asyncio写一个简单的异步爬虫感受一下async/await的用法。理解事件循环这是异步编程的“心脏”花点时间搞懂它。区分场景记住异步不是万能的。它只对 I/O 密集型任务有显著效果不要用它去加速计算。阅读源码看看asyncio库的源码比如Task和Future的实现能帮你彻底理解底层机制。学习生态熟悉aiohttp、aiofiles、asyncpg等库它们是你实际开发中的利器。希望这篇文章能帮你彻底搞懂“异步”以及它周围那些让人头疼的术语。记住这些概念一开始觉得难是正常的多写、多用、多思考慢慢就会融会贯通。