欢迎您访问 最编程 本站为您分享编程语言代码,编程技术文章!
您现在的位置是: 首页

python 并发和并发管道

最编程 2024-05-31 09:28:09
...

协程

Python 协程类似于生成器,但协程主要用作数据使用者,而不是生成数据。换句话说,协程是每次使用 send 方法发送值时恢复的函数。

协程的诀窍是在赋值表达式的右侧使用 yield 关键字。下面是一个协程的示例,它只打印发送到它的值

def coroutine():

    print('My coroutine')

    while True:

        val=yield

        print('Got',val)

>>> co = coroutine()

>>> next(co)

    My coroutine

>>>co.send(1) 
    
    Got 1

>>>co.send(2) 

    Got 2

>>> co.send(3) 

    Got 3

需要对 next 进行初始调用才能向前移动协程。

您可以看到它执行了 print 语句。

最终,该函数到达 yield 表达式,它将在其中等待恢复。然后,每次发送值(使用 send)时,协程函数都会从 yield 恢复,将值复制到 val 并打印出来。

协程可以使用 close() 方法关闭。

>>> co.close()

>>> co.send(4)

Traceback (most recent call last):

    File "<stdin>", line 1, in <module> 

StopIteration

Pipelines

协程可用于实现数据管道,其中一个协程将数据发送到管道中的下一个协程。

协程使用 send() 方法将数据推送到管道中。

image.png

下面是一个小管道的示例,其中发送到生产者协程的值被平方并发送到使用者协程进行打印:

def producer(consumer): 
    
    print("Producer ready") 
    
    while True:

        val=yield

        consumer.send(val *val) 
    
def consumer():

    print("Consumer ready")
    
    while True:

        val=yield
    
        print('Consumer got',val)

如上所述,协程必须与 next “启动”,然后才能发送任何值。

>>> cons = consumer()

>>> prod = producer(cons)

>>>next(prod)

Producer ready

>>>next(cons)

Consumer ready

>>>prod.send(1)

Consumer got 1

>>> prod.send(2)

Consumer got 4

>>>prod.send(3)

Consumer got 9

此外,使用协程,可以将数据发送到多个目标。下面的示例实现两个使用者,其中第一个使用者仅打印 0..10 中的数字,第二个使用者仅打印 10..20 中的数字:

def producer(consumers) :

    print("Producer ready")

    try:

        while True:

            val= yield

            for consumer in consumers:

                consumer.send(val * val)

    except GeneratorEcit:

        for consumer in consumers:

            consumer.close()

def consumer(name, low,high):

    print("%s ready" % name)

    try:

        while True:

            val =yield

            if low < val < high:

                print('%s got' % name, val) 

    except GeneratorExit:

        print("%s closed" % name)

和以前一样,在发送任何值之前,必须“启动”协程。

>>>con1 = consumer('Consumer 1', 00,10)

>>> con2 = consumer('Consumer 2', 10,20)

>>> prod = producer([con1,con2])

>>>next(prod)

Producer ready

>>>next(con1)

onsumer 1 ready

>>> next(con2)

Consumer 2 ready

>>>prod.send(1)

Consumer 1 got 1

>>>prod.send(2)

Consumer 1 got 4

>>>prod.send(3)

Consumer 1 got 9

>>>prod.send(4)

Consumer 2 got 16

>>> prod.close()

Consumer 1 closed 
Consumer 2 closed

数据被发送到所有使用者,但只有第二个执行 print 语句。

请注意 GeneratorExit 异常的使用。有时,捕获异常并通知下游协程管道不再有用可能很有用。

image.png

使用协程管道进行练习

  1. 实现生产者-消费者管道,其中生产者平方的值将发送给两个消费者。 一个应该存储和打印到目前为止发送的最小值,另一个应该存储和打印最大值。

  2. 实施生产者-消费者管道,其中生产者平方的值被调度给两个消费者,一次一个。第一个值应发送到使用者 1,第二个值应发送到使用者 2,第三个值应再次发送到使用者 1,依此类推。关闭生产者应该迫使消费者打印一个列表,其中包含每个人获得的数字。