Python异步: 什么时候使用异步?(3)

简介: 从广义上讲,Asyncio 是新的、流行的、讨论广泛的和令人兴奋的。然而,对于何时应该在项目中采用它存在很多困惑。

我们什么时候应该在 Python 中使用 asyncio?

1. 在 Python 中使用 Asyncio 的原因

在 Python 项目中使用 asyncio 可能有 3 个原因:

  1. 使用 asyncio 以便在您的程序中采用协程。
  2. 使用 asyncio 以使用异步编程范例。
  3. 使用 asyncio 以使用非阻塞 I/O。

1.1. 使用协程

我们可能会选择使用 asyncio,因为我们要使用协程。我们可能想要使用协程,因为我们的程序中可以有比并发线程更多的并发协程。协程是另一个并发单元,就像线程和进程一样。

基于线程的并发由线程模块提供,并由底层操作系统支持。它适用于阻塞 I/O 任务,例如从文件、套接字和设备读取和写入。

基于进程的并发由 multiprocessing 模块提供,也由底层操作系统支持,如线程。它适用于不需要太多进程间通信的 CPU 绑定任务,例如计算任务。

协程是 Python 语言和运行时(标准解释器)提供的替代方案,并由 asyncio 模块进一步支持。它们适用于具有子进程和套接字的非阻塞 I/O,但是,阻塞 I/O 和 CPU 绑定任务可以在幕后使用线程和进程以模拟非阻塞方式使用。

最后一点是微妙而关键的。虽然我们可以选择使用协同程序来实现它们引入 Python 的非阻塞功能,但实际上我们可以将它们用于任何任务。如果我们愿意,任何使用线程或进程编写的程序都可以重写或使用协程编写。

线程和进程通过操作系统选择哪些线程和进程应该运行、何时运行以及运行多长时间来实现多任务处理。操作在线程和进程之间快速切换,挂起那些未运行的并恢复那些被授予运行时间的。这称为抢占式多任务处理。

Python 中的协程提供了另一种多任务处理类型,称为协作多任务处理。协程是可以挂起和恢复的子例程(函数)。它由 await 表达式暂停,并在 await 表达式解析后恢复。这允许协程通过设计进行合作,选择如何以及何时暂停它们的执行。它是一种替代的、有趣的、强大的并发方法,不同于基于线程和基于进程的并发。仅这一点就可能成为在项目中采用它的理由。协程的另一个关键方面是它们是轻量级的。

它们比线程更轻量级。这意味着它们启动速度更快,使用的内存更少。本质上,协程是一种特殊类型的函数,而线程由 Python 对象表示,并与操作系统中的线程相关联,该对象必须与之交互。因此,我们可能在一个 Python 程序中有数千个线程,但我们很容易在一个线程中拥有数万或数十万个协程。

我们可能会选择协程,因为它们具有可扩展性。

1.2. 使用异步编程

我们可能会选择使用asyncio,因为我们想在我们的程序中使用异步编程。也就是说,我们要开发一个使用异步编程范式的Python程序。异步意味着不同时,与同步或同时相反。在编程时,异步意味着请求动作,尽管在请求时并未执行。它稍后执行。异步编程通常意味着全力以赴并围绕异步函数调用和任务的概念设计程序。虽然还有其他方法可以实现异步编程的元素,但 Python 中的完整异步编程需要使用协程和 asyncio 模块。

我们可能会选择使用 asyncio,因为我们想在我们的程序中使用异步编程模块,这是一个有道理的理由。明确地说,这个原因与使用非阻塞 I/O 无关。异步编程可以独立于非阻塞 I/O 使用。正如我们之前看到的,协程可以异步执行非阻塞 I/O,但是 asyncio 模块还提供了以异步方式执行阻塞 I/O 和 CPU 绑定任务的工具,通过线程在幕后模拟非阻塞和过程。

1.3. 使用非阻塞 I/O

我们可能会选择使用 asyncio,因为我们希望或需要在我们的程序中使用非阻塞 I/O。Input/Output 或简称 I/O 是指从资源读取或写入。

常见的例子包括:

  • 硬盘驱动器:读取、写入、追加、重命名、删除等文件。
  • 外设:鼠标、键盘、屏幕、打印机、串口、摄像头等。
  • 互联网:下载和上传文件、获取网页、查询RSS等。
  • 数据库:选择、更新、删除等 SQL 查询。
  • 电子邮件:发送邮件、接收邮件、查询收件箱等。

与用 CPU 计算事物相比,这些操作很慢。这些操作在程序中的常见实现方式是发出读或写请求,然后等待发送或接收数据。因此,这些操作通常称为阻塞 I/O 任务。操作系统可以看到调用线程被阻塞,并将上下文切换到另一个将使用 CPU 的线程。这意味着阻塞调用不会减慢整个系统的速度。但它确实会停止或阻塞进行阻塞调用的线程或程序。

非阻塞 I/O 是阻塞 I/O 的替代方案。它需要底层操作系统的支持,就像阻塞 I/O 一样,所有现代操作系统都提供对某种形式的非阻塞 I/O 的支持。非阻塞 I/O 允许读取和写入调用作为异步请求进行。操作系统将处理请求并在结果可用时通知调用程序。

  • 非阻塞 I/O:通过异步请求和响应执行 I/O 操作,而不是等待操作完成。

因此,我们可以看到非阻塞 I/O 与异步编程的关系。实际上,我们通过异步编程来使用非阻塞I/O,或者通过异步编程实现非阻塞I/O。

非阻塞 I/O 与异步编程的结合是如此普遍,以至于它通常被简称为异步 I/O。

  • 异步 I/O:一种简写,指的是将异步编程与非阻塞 I/O 相结合。

添加 Python 中的 asyncio 模块专门用于向 Python 标准库添加对子进程(例如在操作系统上执行命令)和流(例如 TCP 套接字编程)的非阻塞 I/O 的支持。我们可以使用线程和 Python 线程池或线程池执行器提供的异步编程能力来模拟非阻塞 I/O。asyncio 模块通过协同程序、事件循环和对象来为非阻塞 I/O 提供一流的异步编程,以表示非阻塞子进程和流。

2. 使用 Asyncio 的其他原因

理想情况下,我们会选择一个在项目要求的上下文中得到辩护的理由。有时我们可以控制功能和非功能需求,有时则不能。在我们这样做的情况下,我们可能会出于上述原因之一选择使用 asyncio。在我们不这样做的情况下,我们可能会被引导选择 asyncio 以交付解决特定问题的程序。

我们可能使用 asyncio 的其他一些原因包括:

  1. 使用 asyncio 是因为其他人为您做出了决定。
  2. 使用 asyncio,因为你加入的项目已经在使用它。
  3. 使用 asyncio 是因为您想了解更多有关它的信息。

我们并不总是能够完全控制我们从事的项目。开始一项新工作、新角色或新项目并由直线经理或首席架构师告知特定设计和技术决策是很常见的。

我们可能会在项目上使用 asyncio,因为项目已经在使用它。您必须使用 asyncio,而不是您选择使用 asyncio。我们可能会在项目上使用 asyncio,因为项目已经在使用它。您必须使用 asyncio,而不是您选择使用 asyncio。

一个相关示例可能是您希望采用的使用 asyncio 的问题的解决方案:

  1. 也许您需要使用第三方 API,并且代码示例使用 asyncio。
  2. 也许您需要集成一个使用 asyncio 的现有开源解决方案。
  3. 也许您偶然发现了一些可以满足您需要的代码片段,但它们使用的是 asyncio。

由于缺乏替代解决方案,asyncio 可能会因您选择的解决方案而强加给您。

您可能会选择采用 asyncio 只是因为您想尝试一下,这可能是一个理由。在项目中使用 asyncio 将使它的工作方式具体化。

3. 何时不使用 Asyncio

我们花了很多时间来研究为什么我们应该使用 asyncio。至少花点时间了解为什么我们不应该使用它可能是个好主意。不使用 asyncio 的一个原因是您无法使用上述原因之一来捍卫它的使用。这并非万无一失。可能还有其他使用它的原因,上面没有列出。但是,如果你选择一个使用 asyncio 的理由,而这个理由对你的具体情况来说感觉很薄弱或充满漏洞。也许 asyncio 不是正确的解决方案。我认为不使用 asyncio 的主要原因是它没有提供您认为的好处。

关于 Python 并发性存在许多误解,尤其是围绕 asyncio:

  1. Asyncio 将围绕全局解释器锁工作。
  2. Asyncio 比线程更快。
  3. Asyncio 避免了对互斥锁和其他同步原语的需要。
  4. Asyncio 比线程更容易使用。

以上都是错误的理解!

按照设计,一次只能运行一个协程,它们协作执行。这就像 GIL 下的线程一样。事实上,GIL 是一个正交问题,在大多数情况下使用 asyncio 时可能无关紧要。任何你可以用 asyncio 编写的程序,你都可以用线程编写,而且它可能会一样快或更快。它也可能更简单,更容易被其他开发人员阅读和解释。您可能会想到线程的任何并发故障模式,您都可能会遇到协程。您必须使协同程序免受死锁和竞争条件的影响,就像线程一样。

不使用 asyncio 的另一个原因是你不喜欢异步编程。

异步编程在许多不同的编程社区中流行了一段时间,最著名的是 JavaScript 社区。它不同于过程式、面向对象和函数式编程,一些开发人员就是不喜欢它。

现在我们已经熟悉了何时使用 asyncio,让我们更详细地了解协程。

相关文章
|
2月前
|
并行计算 数据处理 Python
Python并发编程迷雾:IO密集型为何偏爱异步?CPU密集型又该如何应对?
在Python的并发编程世界中,没有万能的解决方案,只有最适合特定场景的方法。希望本文能够为你拨开迷雾,找到那条通往高效并发编程的光明大道。
47 2
|
3月前
|
开发框架 并行计算 算法
揭秘Python并发神器:IO密集型与CPU密集型任务的异步革命,你竟还傻傻分不清?
揭秘Python并发神器:IO密集型与CPU密集型任务的异步革命,你竟还傻傻分不清?
50 4
|
15天前
|
数据采集 JSON 测试技术
Grequests,非常 Nice 的 Python 异步 HTTP 请求神器
在Python开发中,处理HTTP请求至关重要。`grequests`库基于`requests`,支持异步请求,通过`gevent`实现并发,提高性能。本文介绍了`grequests`的安装、基本与高级功能,如GET/POST请求、并发控制等,并探讨其在实际项目中的应用。
24 3
|
2月前
|
关系型数据库 MySQL 数据处理
探索Python中的异步编程:从asyncio到异步数据库操作
在这个快节奏的技术世界里,效率和性能是关键。本文将带你深入Python的异步编程世界,从基础的asyncio库开始,逐步探索到异步数据库操作的高级应用。我们将一起揭开异步编程的神秘面纱,探索它如何帮助我们提升应用程序的性能和响应速度。
|
2月前
|
调度 Python
深入理解 Python 中的异步操作 | python小知识
在现代编程中,异步操作是一个非常重要的概念,尤其是在处理 I/O 密集型任务时。使用异步操作可以显著提高程序的性能和响应速度。Python 提供了 `async` 和 `await` 关键字,使得编写异步代码变得更加直观和简洁【10月更文挑战第8天】
31 2
|
2月前
|
数据采集 前端开发 NoSQL
Python编程异步爬虫实战案例
Python编程异步爬虫实战案例
72 2
|
1月前
|
NoSQL 关系型数据库 MySQL
python协程+异步总结!
本文介绍了Python中的协程、asyncio模块以及异步编程的相关知识。首先解释了协程的概念和实现方法,包括greenlet、yield关键字、asyncio装饰器和async/await关键字。接着详细讲解了协程的意义和应用场景,如提高IO密集型任务的性能。文章还介绍了事件循环、Task对象、Future对象等核心概念,并提供了多个实战案例,包括异步Redis、MySQL操作、FastAPI框架和异步爬虫。最后提到了uvloop作为asyncio的高性能替代方案。通过这些内容,读者可以全面了解和掌握Python中的异步编程技术。
47 0
|
2月前
|
数据处理 Python
深入探索:Python中的并发编程新纪元——协程与异步函数解析
深入探索:Python中的并发编程新纪元——协程与异步函数解析
29 3
|
3月前
|
数据库 开发者 Python
实战指南:用Python协程与异步函数优化高性能Web应用
在快速发展的Web开发领域,高性能与高效响应是衡量应用质量的重要标准。随着Python在Web开发中的广泛应用,如何利用Python的协程(Coroutine)与异步函数(Async Functions)特性来优化Web应用的性能,成为了许多开发者关注的焦点。本文将从实战角度出发,通过具体案例展示如何运用这些技术来提升Web应用的响应速度和吞吐量。
34 1
|
3月前
|
调度 Python
揭秘Python并发编程核心:深入理解协程与异步函数的工作原理
在Python异步编程领域,协程与异步函数成为处理并发任务的关键工具。协程(微线程)比操作系统线程更轻量级,通过`async def`定义并在遇到`await`表达式时暂停执行。异步函数利用`await`实现任务间的切换。事件循环作为异步编程的核心,负责调度任务;`asyncio`库提供了事件循环的管理。Future对象则优雅地处理异步结果。掌握这些概念,可使代码更高效、简洁且易于维护。
31 1