Python并发之协程gevent数据结构和实践(6)

greenlet instances 之间的关系存在两种:仅有包含于 greenlet instances 集合的关系 同步关系,即存在协作关系第一种形式很常见,不同的 greenlet instance 之间没有交流,且没有共享数据需要进行操作,各自做各自的事情。对于第二种形式,gevent 提供了几种数据结构便于 greenlet instances 间进行同步。Gevent常用...
摘要由CSDN通过智能技术生成

greenlet instances 之间的关系存在两种:

  • 仅有包含于 greenlet instances 集合的关系
  • 同步关系,即存在协作关系

第一种形式很常见,不同的 greenlet instance 之间没有交流,且没有共享数据需要进行操作,各自做各自的事情。
对于第二种形式,gevent 提供了几种数据结构便于 greenlet instances 间进行同步。

Gevent常用数据结构和多进程/线程类似,有以下7种:

  • 事件
  • 队列
  • 组和池
  • 锁和信号量
  • 线程局部变量
  • 子进程
  • Actors

1,事件

事件(event)是一个在Greenlet之间异步通信的形式。

gevent.event.Event

通过这种同步原语可以控制一个 greenlet 与多个 greenlet 通过 flag 的 True/False 值进行同步,Event instance 的初始 flag 是 False.但这种同步是 一次性的,即 set() 设置 flag 为 True 对之前因为 wait() 阻塞的 greenlets 都有效,但对 set() 之后再次设置wait() 的 greenlet 无效。
一般的使用场景是:一个 greenlet 控制何时通过 Event().set() 方法设置 
flag 的值为 True 来控制其它协作的 greenlet 运行,有协作关系的 greenlet 通过 Event().wait() 方法等待 flag 被设为 True,否则一直阻塞。

代码示例:

import gevent
from gevent.event import Event

'''
Illustrates the use of events
'''

evt = Event()

def setter():
    '''After 3 seconds, wake all threads waiting on the value of evt'''
    print('厨师开始做菜')
    gevent.sleep(3)
    print("菜做好了")
    evt.set() #设置event的flag为True,所有wait的greenlet解除阻塞

def waiter(name):
    '''After 3 seconds the get call will unblock'''
    print("{} 服务员等菜".format(name))
    evt.wait()  # 阻塞,跳转到下一个greenlet
    print("菜好了, {} 送餐".format(name))

def main():
    gevent.joinall([
        gevent.spawn(setter),
        gevent.spawn(waiter, "服务员 A"),
        gevent.spawn(waiter, "服务员 B"),
    ])

if __name__ == '__main__':
    main()

运行结果:

厨师开始做菜
服务员 A 服务员等菜
服务员 B 服务员等菜
菜做好了
菜好了, 服务员 A 送餐
菜好了, 服务员 B 送餐

这里setter和waiter一共起了三个协程。分析一下运行顺序应该很容易了解evt是干嘛的:

首先回调之行到运行setter 打印str然后gevent.sleep(3);

然后执行第二个回调waitter()执行到evt.wait()的时候阻塞住然后切换到下一个greenlet实例,执行第三个回调waitter()执行到evt.wait()又被阻塞了,这个时候继续执行下一个回调就会回到setter里面,因为没有人在他前面往hub.loop里注册了;

之后这里执行【print("菜做好了")】,运行evt.set()将flag设置为True。

然后另外两个被阻塞的waitter的evt.wait()方法在看到flag已经为True之后不再继续阻塞运行并且结束。

可以看到,Event可以协同好几个Greenlet同时工作,并且一个主Greenlet在操作的时候可以让其他几个都处于等待的状态,可以实现一些特定的环境和需求。

注意:

一旦 flag 被设为了 True,之前所有的Event().wait() 操作将不再阻塞,这些 greenlet 将等待 hub greenlet 进行调度,即使之后 _flag 又被设置为了 False。可参考这个 问题,还可以再对比一个程序理解这点儿,参考 这个

若出现 wait() 处于永远的阻塞状态,即在 wait() 设置之后,在其它 greenlet 中没有 set() 操作,则 gevent 会抛出这样的异常。

示例代码:

import random

import gevent
from gevent.event import Event


class TestEvent(object):
    def __init__(self):
        self.event = Event()

    def run(self):
        producers = [gevent.spawn(self._producer, i) for i in range(3)]
        consumers = [gevent.spawn(self._consumer, i) for i in range(3)]
        tasks = []
        tasks.extend(producers)
        tasks.extend(consumers)
        gevent.joinall(tasks)

    def _producer(self, pid):
        print("I'm producer %d and now I don't want consume to do something" % (pid,))
        self.event.clear()
        sleeptime = random.randint(0, 5) * 0.01
        print("Sleeping time is %f" % (sleeptime,))
        gevent.sleep(sleeptime)
        print("I'm producer %d and now consumer could do something." % (pid,))
        self.event.set()

    def _consumer(self, pid):
        print("I'm consumer %d and now I'm waiting for producer" % (pid,))
        gevent.sleep(random.randint(0, 10) * 0.1)
        flag = self.event.wait()
        print("I'm consumer %d. Flag is %r and now I can do something" % (pid, flag))
        self.event.clear()


if __name__ == '__main__':
    test = TestEvent()
    test.run()

执行结果:

I'm producer 0 and now I don't want consume to do something
Sleeping time is 0.020000
I'm producer 1 and now I don't want consume to do something
Sleeping time is 0.000000
I'm producer 2 and now I don't want consume to do something
Sleeping time is 0.020000
I'm consumer 0 and now I'm waiting for producer
I'm consumer 1 and now I'm waiting for producer
I'm consumer 2 and now I'm waiting for producer
I'm producer 1 and now consumer could do something.
I'm producer 0 and now consumer could do something.
I'm producer 2 and now consumer could do something.
I'm consumer 2. Flag is True and now I can do somet
  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值