📅  最后修改于: 2020-04-07 05:30:26             🧑  作者: Mango
先决条件:生成器
我们都熟悉函数,也称为子例程,过程,子过程等。函数是一系列指令,打包成一个单元来执行特定任务。如果将复杂功能的逻辑分为几个独立的步骤,这些步骤本身就是函数,则这些函数称为辅助函数或子例程。
Python中的子例程由main函数调用,该函数负责协调这些子例程的使用。子例程具有单个入口点。
协程是子例程的泛化。它们用于协作式多任务处理,在协作式多任务处理中,process会定期或在空闲时自动产生(或放弃)控制,以使多个应用程序能够同时运行。协程和子例程之间的区别是:
协程与线程
现在您可能正在考虑协程与线程有何不同,两者似乎都可以完成相同的工作。
如果是线程,则是操作系统(或运行时环境)根据调度程序在线程之间切换。在协程的情况下,是由程序员和编程语言来决定何时切换协程。协同程序通过程序员在设定点处挂起和恢复来协同工作多个任务。
Python协程
在Python中,协程与生成器相似,但是协程很少,并且我们使用yield语句的方式略有变化。生成器产生用于迭代的数据,而协程也可以消耗数据。
在Python 2.5中,对yield语句进行了一些修改,现在yield也可以用作expression。例如,在赋值语句的右侧:
line = (yield)
我们发送给协程的任何值都被(yield)表达式捕获并返回。
可以通过send()方法将值发送到协程。例如,考虑如下协程,该协程打印出带有前缀“ Dear”的名称。我们将使用send()方法将名称发送到协程。
# Python3展示协程
def print_name(prefix):
print("搜索前缀:{}".format(prefix))
while True:
name = (yield)
if prefix in name:
print(name)
# 调用协程, 什么也不会发生
corou = print_name("Dear")
# 这回开始执行协程
# 打印第一行‘搜索前缀’
# 并一直执行到第一个yield表达式
corou.__next__()
# 发出输出
corou.send("mango")
corou.send("Dear mango")
输出:
搜索前缀:Dear
Dear mango
协程的执行
协程的执行类似于生成器。当我们调用协程时,什么也没有发生,它仅在响应next()和send()方法时运行。在上面的示例中可以清楚地看到这一点,因为只有在调用__next __()方法之后,协程才开始执行。调用之后,执行前进到第一个yield表达式,现在执行暂停并等待将值发送到协程对象。当第一个值发送给它时,它将检查前缀和打印名称(如果存在前缀)。打印名称后,它将经历循环,直到再次遇到name =(yield)表达式为止。
关闭协程
协程可能会无限期运行,关闭协程使用close()方法。当协程关闭时,它会生成GeneratorExit异常,可以按常规方式捕获该异常。关闭协程后,如果我们尝试发送值,它将引发StopIteration异常。以下是一个简单的示例:
# Python3展示关闭协程
def print_name(prefix):
print("搜索前缀:{}".format(prefix))
try :
while True:
name = (yield)
if prefix in name:
print(name)
except GeneratorExit:
print("关闭协程!!")
corou = print_name("Dear")
corou.__next__()
corou.send("mango")
corou.send("Dear mango")
corou.close()
输出:
搜索前缀:Dear
Dear mango
关闭协程!!
链接协程以创建管道
协程可以用来设置管道。我们可以将协程链接在一起,并使用send()方法通过管道推送数据。管道需要:
以下是链接的一个简单示例:
# Python3展示链接协程
def producer(sentence, next_coroutine):
'''
Producer把string分开,送给pattern_filter
'''
tokens = sentence.split(" ")
for token in tokens:
next_coroutine.send(token)
next_coroutine.close()
def pattern_filter(pattern="ing", next_coroutine=None):
'''
在接收到的令牌中搜索模式,如果模式匹配,则将其发送到print_token()协程进行打印
'''
print("搜索 {}".format(pattern))
try:
while True:
token = (yield)
if pattern in token:
next_coroutine.send(token)
except GeneratorExit:
print("过滤完毕!!")
def print_token():
'''
充当接收器,只需打印接收到的令牌
'''
print("这是一个水槽,会打印tokens")
try:
while True:
token = (yield)
print(token)
except GeneratorExit:
print("打印完毕!")
pt = print_token()
pt.__next__()
pf = pattern_filter(next_coroutine = pt)
pf.__next__()
sentence = "Bob is running behind a fast moving car"
producer(sentence, pf)
输出:
这是一个水槽,会打印tokens
搜索
running
moving
过滤完毕!!
打印完毕!