Python 简明教程

Python - Coroutines

Python Coroutines 是编程中的基本概念,它扩展了传统函数的功能。它们对于异步编程和复杂的数据处理管道特别有用。

Coroutines 是函数和生成器的概念的扩展。它们被设计用于执行协作多任务并管理异步操作。

在传统函数中,即单一入口和出口点的子例程,而协程可以在恢复的时候暂停和恢复执行,使其具有很高的灵活性。

Key Characteristics of Coroutines

以下是 Python 中协程的关键特性 −

  1. Multiple Entry Points: 协程不像传统函数那样局限于单一入口点。当它们遇到 yield 语句时,可以在特定点暂停执行,然后稍后恢复。这使协程能够处理等待异步数据或处理此数据的复杂工作流。

  2. No Central Coordinator: 当我们看到传统函数(即子例程),它通常由主函数协调;而协程则更独立地运行。它们可以在管道模式下相互交互,其中数据流经一系列协程,而每个协程都执行不同的任务。

  3. Cooperative Multitasking: 协程启用协作多任务。这意味着,调度程序控制协程的产生和恢复,而不是依赖操作系统或运行时在任务之间切换,从而允许对执行流进行更细粒度的控制。

Subroutines Vs. Coroutines

Subroutines 是具有单个入口点且没有固有暂停或恢复执行机制的传统函数。它们按定义的顺序调用,并处理具有简单控制流的任务。

Coroutines 是具有多个入口点的高级函数,可以暂停和恢复其执行。它们对于需要异步执行、复杂控制流和数据管道的重要任务十分有用。它们支持协作多任务,允许调度程序控制任务之间的执行切换。

下表有助于理解子例程和协程之间的关键差异和相似之处,让我们更容易掌握它们在编程中的各自作用和功能。

Execution of Coroutines

Coroutines 由 * next ()* 方法启动,它启动协程并将执行推进到第一个 yield 语句。然后协程等待发送到它其中的一个值。 send() 方法用于向协程发送值,这些值随后可以处理这些值并可能产生结果。

Example of Basic Coroutine

协程使用既可以发送又可以接收值的 yield 语句。与为迭代产生值的 generator 不同,协程通常使用 yield 来接收输入并根据该输入执行动作。以下是 Python 协程的基本示例 −

def print_name(prefix):
    print(f"Searching prefix: {prefix}")
    while True:
        name = (yield)
        if prefix in name:
            print(name)

# Instantiate the coroutine
corou = print_name("Welcome to")

# Start the coroutine
corou.__next__()

# Send values to the coroutine
corou.send("Tutorialspoint")
corou.send("Welcome to Tutorialspoint")

Output

Searching prefix: Welcome to
Welcome to Tutorialspoint

Closing a Coroutine

Coroutines 可以无限期运行,因此在不需要它们时正确关闭它们非常重要。 close() 方法终止协程并处理清理。如果我们尝试向已关闭的协程发送数据,它将引发 StopIteration exception.

Example

以下是 Python 中关闭协程的示例 −

def print_name(prefix):
    print(f"Searching prefix: {prefix}")
    try:
        while True:
            name = (yield)
            if prefix in name:
                print(name)
    except GeneratorExit:
        print("Closing coroutine!!")

# Instantiate and start the coroutine
corou = print_name("Come")
corou.__next__()

# Send values to the coroutine
corou.send("Come back Thank You")
corou.send("Thank you")

# Close the coroutine
corou.close()

Output

Searching prefix: Come
Come back Thank You
Closing coroutine!!

Chaining Coroutines for Pipelines

Coroutines 可以链接在一起形成处理管道,允许数据流经一系列阶段。这对于分阶段处理数据序列特别有用,其中每个阶段执行特定任务。

Example

以下是展示用于管道的协程链接示例 −

def producer(sentence, next_coroutine):
   '''
   Splits the input sentence into tokens and sends them to the next coroutine.
   '''
   tokens = sentence.split(" ")
   for token in tokens:
      next_coroutine.send(token)
   next_coroutine.close()

def pattern_filter(pattern="ing", next_coroutine=None):
   '''
   Filters tokens based on the specified pattern and sends matching tokens to the next coroutine.
   '''
   print(f"Searching for {pattern}")
   try:
      while True:
         token = (yield)
         if pattern in token:
            next_coroutine.send(token)
   except GeneratorExit:
      print("Done with filtering!!")
      next_coroutine.close()

def print_token():
   '''
   Receives tokens and prints them.
   '''
   print("I'm the sink, I'll print tokens")
   try:
      while True:
         token = (yield)
         print(token)
   except GeneratorExit:
      print("Done with printing!")

# Setting up the pipeline
pt = print_token()
pt.__next__()

pf = pattern_filter(next_coroutine=pt)
pf.__next__()

sentence = "Tutorialspoint is welcoming you to learn and succeed in Career!!!"
producer(sentence, pf)

Output

I'm the sink, I'll print tokens
Searching for ing
welcoming
Done with filtering!!
Done with printing!