翻译仅便于个人学习,熟悉英语的请阅读原文
目录
Python资源共享群:484031800
- asyncio 包和 async/awaitasync/await 语法和原生协程
- 生成器中异步IO的Roots
- 其他特点: async for and Async Generators + Comprehensions
- 事件循环和 asyncio.run()
- 一个完整的程序:异步请求
- 何时以及为何异步IO是正确的选择?
- Async IO It Is, but Which One?
Async IO是一种并发编程设计,Python中已经有了独立的支持,并且从Python3.4到Python3.7得到了快速发展。
你可能疑惑,“并发、并行、线程、多处理”。MMP这已经很多了,异步IO是哪根葱?”
本教程旨在帮助你回答这个问题,让你更牢固地掌握Python的异步IO。
以下是要介绍的内容:
- 异步IO :一种与语言无关的范例(模型),它具有许多跨编程语言的实现
- async/await :两个 用于定义协程的新Python关键字
- asyncio :为运行和管理协程提供基础和API的Python包/库
协程(专用生成器函数)是Python中异步IO的核心,稍后我们将深入研究它们。
注意:在本文中,使用术语 异步IO 来表示与语言无关的异步IO设计,而 asyncio 指的是Python包。
开始之前,你需要确保已经配置搭建了可以使用 asyncio 及其他库的实验环境。
搭建自己的实验环境
你需要安装Python 3.7+以及 aiohttp 和 aiofiles 包才能完整地跟随本文进行实验。
$ python3.7 -m venv ./py37async $ source ./py37async/bin/activate # Windows: .\py37async\Scripts\activate.bat $ pip install --upgrade pip aiohttp aiofiles # 可选项: aiodns
有关安装Python 3.7和设置虚拟环境的帮助,请查看 Python 3安装和设置指南 或 虚拟环境基础
ok,let's go!
异步IO鸟瞰图
相较于它久经考验的表亲(多进程和多线程)来说,异步IO不太为人所知。本节将从高层全面地介绍异步IO是什么,以及哪些场景适合用它。
哪些场景适合异步IO?
并发和并行是个非常广泛的主题。因为本文重点介绍异步IO及其在Python中的实现,现在值得花一点时间将异步IO与其对应物进行比较,以了解异步IO如何适应更大、有时令人眼花缭乱的难题。
并行:同时执行多个操作。
多进程:是一种实现并行的方法,它需要将任务分散到计算机的中央处理单元(cpu或核心)上。多进程非常适合cpu密集的任务:密集for循环和密集数学计算通常属于这一类。
并发:并发是一个比并行更广泛的术语。 它表明多个任务能够以重叠方式运行。 (有一种说法是并发并不意味着并行。)
线程:是一种并发执行模型,多个线程轮流执行任务。 一个进程可以包含多个线程。 由于GIL(全局解释器锁)的存在,Python与线程有着复杂的关系,但这超出了本文的范围。
了解线程的重要之处是它更适合于io密集的任务。cpu密集型任务的特点是计算机核心从开始到结束都在不断地工作,而一个IO密集型任务更多的是等待IO的完成。
综上所述,并发既包括多进程(对于CPU密集任务来说是理想的),也包括线程(对于IO密集型任务来说是理想的)。多进程是并行的一种形式,并行是并发的一种特定类型(子集)。Python通过 multiprocessing , threading , 和 concurrent.futures 标准库为这两者提供了长期支持。
现在是时候召集一名新成员了!在过去的几年里,一个独立的设计被更全面地嵌入到了CPython中:通过标准库的 asyncio 包和新的 async/await 语言关键字实现异步IO。需要说明的是,异步IO不是一个新发明的概念,它已经存在或正在构建到其他语言和运行时环境中,比如Golang、C#或者Scala。
Python文档将 asyncio 包称为 用于编写并发代码的库 。然而,异步IO既不是多线程也不是多进程,它不是建立在其中任何一个之上。事实上异步IO是一种单进程单线程设计:它使用 协作式多任务操作方式 ,在本教程结束时你将理解这个术语。换句话说,尽管在单个进程中使用单个线程,但异步IO给人一种并发的感觉。协程(异步IO的一个核心特性)可以并发地调度,但它们本质上不是并发的。
重申一下,异步输入输出是并发编程的一种风格,但不是并行的。与多进程相比,它与线程更紧密地结合在一起,但与这两者截然不同,并且是并发技术包中的独立成员。
现在还留下了一个词没有解释。 异步是什么意思?这不是一个严格的定义,但是对于我们这里的目的,我可以想到/考虑到两个属性:
- 异步例程能够在等待其最终结果时“暂停”,并允许其他例程同时运行。
- 通过上面的机制,异步代码便于并发执行。 换句话说,异步代码提供了并发的外观和感觉
下面是一个一个将所有内容组合在一起的图表。 白色术语代表概念,绿色术语代表实现或实现它们的方式:
(Concurrencey并发、Threading线程、Async IO异步IO、Parallelism并行、Multiprocessing多进程)
我将在这里停止对并发编程模型的比较。本教程重点介绍异步IO的子组件,如何使用它、以及围绕它创建的API。要深入研究线程、多处理和异步IO,请暂停这里并查看Jim Anderson对(Python中并发性的概述)[https://realpython.com/python-concurrency/]。Jim比我有趣得多,而且参加的会议也比我多。
译者注 :要了解多种并发模型的比较,可以参考(《七周七并发模型》 )
异步IO释义
异步IO乍一看似乎违反直觉,自相矛盾。如何使用一个线程和一个CPU内核来简化并发代码?我从来都不擅长编造例子,所以我想借用 Miguel Grinberg2017年PyCon演讲 中的一个例子,这个例子很好地解释了一切:
国际象棋大师JuditPolgár举办了一个国际象棋比赛,在那里她扮演多个业余选手。 她有两种方式进行比赛:同步和异步。
假设:
- 24个对手
- Judit在5秒钟内完成一个棋子的移动
- 每个对手移动一个棋子需要55秒
- 游戏平均30对移动(总计60次移