乐趣区

关于程序员:Python-异步-协程4

Python 提供一流的协程,具备“coroutine”类型和新的表达式,如“async def”和“await”。它提供了用于运行协程和开发异步程序的“asyncio”模块。

在本节中,咱们将更深刻地理解协程。

1. 什么是协程

协程是一个能够挂起和复原的函数。它通常被定义为通用子程序。能够执行子程序,从一点开始,在另一点完结。然而,协程能够执行而后挂起,并在最终终止之前复原屡次。具体来说,协程能够管制它们暂停执行的确切工夫。这可能波及特定表达式的应用,例如 Python 中的“await”表达式,如 Python 生成器中的 yield 表达式。

协程可能因多种起因而暂停,例如执行另一个协程,例如期待另一个工作,或期待一些内部资源,如套接字连贯或过程返回数据。

协程用于并发。能够同时创立和执行许多协程。它们能够管制何时挂起和复原,从而容许它们在并发工作执行时进行单干。这称为合作式多任务处理,不同于通常与线程一起应用的多任务处理,称为抢占式多任务处理。抢占式多任务波及操作系统抉择暂停和复原哪些线程以及何时这样做,而不是在合作多任务的状况下由工作本人决定。

当初咱们对什么是协程有了一些理解,让咱们通过将它们与其余相熟的编程构造进行比拟来加深这种了解。

2. 协程与例程和子例程

“例程”和“子例程”在古代编程中通常指的是同一事物。兴许更精确地说,例程是程序,而子例程是程序中的函数。例程有子例程。它是一个离散的表达式模块,它被调配了一个名称,能够承受参数并能够返回一个值。

  • 子例程:可按需执行的指令模块,通常已命名,可采纳参数并返回值。也称为函数

一个子程序被执行,遍历表达式,并以某种形式返回。通常,一个子程序被另一个子程序调用。协程是子例程的扩大。这意味着子例程是一种非凡类型的协程。

协程在很多方面都像子例程,例如:

  • 它们都是离散的命名表达式模块。
  • 他们都能够承受争执,也能够不承受。
  • 它们都能够返回一个值,也能够不返回。

次要的区别在于它在返回和退出之前抉择了屡次暂停和复原执行。协程和子例程都能够调用本人的其余实例。一个子程序能够调用其余子程序。协程执行其余协程。然而,协程也能够执行其余子例程。当一个协程执行另一个协程时,它必须暂停执行并容许另一个协程在另一个协程实现后复原。这就像一个子程序调用另一个子程序。不同之处在于协程的暂停可能容许任意数量的其余协程也运行。这使得调用另一个协程的协程比调用另一个子例程的子例程更弱小。它是协同程序促成的合作多任务处理的外围。

3. 协程与生成器

生成器是一种能够暂停其执行的非凡函数。生成器函数能够像一般函数一样定义,只管它在暂停执行并返回值时应用 yield 表达式。生成器函数将返回一个能够遍历的生成器迭代器对象,例如通过 for 循环。每次执行生成器时,它都会从上一次挂起的点运行到下一个 yield 语句。

协程能够应用“await”表达式挂起或屈服于另一个协程。一旦期待的协同程序实现,它将从这一点复原。咱们可能会将生成器视为循环中应用的一种非凡类型的协程和合作多任务处理。

在协程被开发之前,生成器被扩大,以便它们能够像 Python 程序中的协程一样应用。这须要大量的生成器技术常识和自定义任务调度程序的开发。这是通过更改生成器和引入“yield from”表达式实现的。

这些起初被弃用,取而代之的是古代的 async/await 表达式。

4. 协程与工作

子例程和协程可能代表程序中的“工作”。然而,在 Python 中,有一个称为 asyncio.Task 对象的特定对象。

协程能够包装在 asyncio.Task 对象中并独立执行,而不是间接在协程中执行。Task 对象提供异步执行协程的句柄。

  • Task:一个能够独立执行的包装协程。

这容许包装的协程在后盾执行。调用协程能够继续执行指令而不是期待另一个协程。Task 不能独自存在,它必须包装一个协程。因而,Task 是协程,但协程不是工作。

5. 协程与线程

协程比线程更轻量级。

  • Thread:与协程相比重量级
  • Coroutine:与线程相比是轻量级的。

协程被定义为一个函数。线程是由底层操作系统创立和治理的对象,在 Python 中示意为 threading.Thread 对象。

  • Thread:由操作系统治理,由 Python 对象示意。

这意味着协程通常能够更快地创立和开始执行并且占用更少的内存。反之,线程的创立和启动速度比协程慢,占用的内存也更多。协程在一个线程内执行,因而一个线程能够执行多个协程。

6. 协程与过程

协程比过程更轻量级。事实上,线程比过程更轻量级。过程是计算机程序。它可能有一个或多个线程。Python 过程实际上是 Python 解释器的一个独自实例。

过程与线程一样,由底层操作系统创立和治理,并由 multiprocessing.Process 对象示意。

  • Process:由操作系统治理,由 Python 对象示意。

这意味着协程的创立和启动速度显著快于过程,并且占用的内存也少得多。协程只是一个非凡的函数,而过程是至多有一个线程的解释器实例。

7. 什么时候将协程增加到 Python

协程扩大了 Python 中的生成器。长期以来,生成器始终在缓缓地向一流的协程迁徙。咱们能够摸索 Python 的一些次要变动以增加协程,咱们能够将其视为概率增加 asyncio 的一个子集。像 send() 和 close() 这样的新办法被增加到生成器对象中,以容许它们更像协程。

第二种基于生成器的协程办法被增加到 Python 3.4 作为 Python 生成器的扩大。协程被定义为应用 @asyncio.coroutine 装璜器的函数。协程是通过 asyncio 模块应用 asyncio 事件循环执行的。协程能够通过“yield from”表达式挂起并执行另一个协程

# define a custom coroutine in Python 3.4
@asyncio.coroutine
def custom_coro():
    # suspend and execute another coroutine
    yield from asyncio.sleep(1)

“yield from”表达式依然可用于生成器,只管它是一种在协程中暂停执行的弃用办法,有利于“await”表达式。

咱们能够说协程是在 Python 3.5 版本中作为一等对象增加的。这包含对 Python 语言的更改,例如“async def”、“await”、“async with”和“async for”表达式,以及协程类型。

本文由 mdnice 多平台公布

退出移动版