关于Gevent的那些事儿

Comments(13)


Posted on 2014-01-22 12:35:42 gevent


1. spawn一个greenlet之后,不会立即运行。

除非有隐式或者显示的手段switch到这个greenlet。

2. gevent.spawn做了什么?

只是创建了一个greenlet实例,并加入到了greenlet链,还没有运行它。

3. greenlet.switch到底做了什么?

greenlet.switch最终会调用greenlet.c中的C函数。 greenlet.c中g_swith会扫描greenlet链,如果发现没有启动的greenlet,则调用g_initialstub启动它。 实际上g_initialstub会在greenlet类实例中查找run属性,找到了则运行它。 如果greenlet是已经启动的,则switch到main hub.

4. g=gevent.spawn(func); g.run()做了什么?

按照3的说法,它首先创建了greenlet实例,设置了实例的’run’属性。 然后直接运行刚才指定的’run’属性,也可以叫它callback,是一个callable对象。

5. 当创建多个greenlet实例,然后并不run他们。

最后再启动一个greenlet,为什么之前创建的greenlet还是可以运行?

因为最后运行的那个greenlet中,发生了switch,对应到greenlet.c中的g_swith。 它会扫描greenlet链,如果发现没有启动的greenlet则启动它们。 如果最后运行的那个greenlet中没有发生switch,则在它之前创建的greenlet无法运行。

例如下面的代码:

def g1():
    print 'g1'
    gevent.sleep(2)

def g2():
    print 'g2'
    gevent.sleep(2)

def g3():
    print 'g3'                                                                                                                    
    gevent.sleep(1)

gevent.spawn(g1)
gevent.spawn(g2)
gevent.spawn(g3).run()

输出:

g3
g1
g2

如果函数g3,没有最后一行gevent.sleep(1), 则g1和g2都不会执行 只是输出’g3’字符串之后,进程退出。

6. hub.Waiter类有什么作用?

Waiter用来在greenlet之间通信,它简单包装了greenlet.swith。 典型的工作过程如下:

>>> result = Waiter() #1
>>> timer = get_hub().loop.timer(0.1) #2
>>> timer.start(result.switch, 'hello from Waiter') #3
>>> result.get() #4
'hello from Waiter'
  • #1: 创建一个Waiter类实例,在init中什么也不做。

  • #2: 启动一个libev的watcher(libev有许多watcher例如io/timer/signal等,可以理解为对特定对象的#监视对象#)

  • #3: 为这个#监视对象#设置callback和参数,这里的是Waiter实例的switch函数,参数为字符串。 接着立即让libev开始监视这个对象。 timer.start只是让libev启动一个time类型的watcher,并在事件发生后,执行回调。 waiter.switch的代码只有关键的一行:greenlet.switch(value),它切换当前协程到main hub. 但是watcher并没有执行result.switch,只是将它加入了libev的callback列表。 要等待libev.loop.run启动主循环。 记住,这里给libev的watcher传递了一个callback,并带有参数。

  • #4: 这里很关键, waiter.get中有self.hub.switch(),表示立即出让时间片到main hub. 流程到了hub.switch这里,它调用greenlet.switch(self)。 这里的greenlet是C代码中的greenlet类实例,是所有greenlet的父类。 所以我们到了greenlet.so模块内部。

    注意这时,虽然main hub已经被创建了,但是从来没有运行过。 所以greenlet.c中switch会调用g_initialstub执行main hub的run函数,这里会启动core.so->loop.run,启动libev的 ioloop.

    因为#3给libev的callback中增加了watcher(waiter.switch),所以ioloop启动后会检测watcher事件,事件发生后调用watcher的callback.

    就会调用waiter.switch,其中一行代码:self.greenlet.switch(value) 因为我们一直在main hub中,所以又回到了hub.switch,在hub.switch中是return greenlet.switch(self),所以这里会返回。 流程最后又回到了wait.get中,其中returen hub.switch()返回最终的值。

7. gevent.sleep到底做了什么?

结合Waiter是如何工作的,再看sleep的代码:

def sleep(seconds=0, ref=True):
    # 得到main hub
    hub = get_hub()

    # 得到hub.loop,这是libev的主循环
    loop = hub.loop

    # 如果sleep时间小于等于0
    # 启动一个waiter,直接调用loop的run_callback运行waiter.switch
    # 再调用waiter.get()会立即返回
    # 因为我们没有给core.so->loop传递任何watcher,所以会立即返回
    if seconds <= 0:
        waiter = Waiter()
        loop.run_callback(waiter.switch)
        waiter.get()
    else:
        # 这里启动了一个libev的timer类型的watcher
        # 然后传递给hub.wait
        # hub.wait的代码,是Waiter类的典型用法:
        # waiter = Waiter()
        # unique = object()
        # watcher.start(waiter.switch, unique)
        # try:
        #      result = waiter.get()
        #      assert result is unique, 'Invalid switch'
        # finally:
        #      watcher.stop()
        # 启动一个timer类型的watcher,
        # 在waiter.get中切换到main hub,然后在事件发生后调用waiter.switch
        # 在waiter.switch中,执行self.greenlet.switch,控制流又会回到waiter.get中
        # 因为self.greenlet是调用waiter.get的协程,也就是调用gevent.sleep的协程
        hub.wait(loop.timer(seconds, ref=ref))
8. monkey.patch_xxx很邪恶
  • 首先monkey.patch_xxx只需要执行一次即可,即在main中执行.

  • 其次monkey.patch_all会给所有模块做patch. 解决办法是,只使用特定模块的patch,如monkey.patch_socket

  • 最后monkey.patch_xxx会给所有导入的模块做patch 解决办法是在其他需要导入的模块执行下面的操作:

    import a
    import socket
    reload(socket)
    print socket.socket     # <class 'socket._socketobject'> 
    
前一篇: 更改linux栈空间大小 后一篇: linux下的自动编译工具

Captcha:
验证码

Email:

Content: (Support Markdown Syntax)


2BAPXOuMHfq  2015-09-11 08:21:48 From 188.143.234.155

That’s a weluoth-lght-out answer to a challenging question


viagra what does it look like  2021-08-29 17:59:29 From 127.0.0.1

Keflex Dose For Dog


Jesevemia  2021-11-13 21:27:35 From 127.0.0.1

Prednisone


Irramyrex  2021-12-03 23:44:33 From 127.0.0.1

hydroxychloroquine for sale online


plaquenil immunosuppression  2021-12-07 07:45:45 From 127.0.0.1

Kamagra Vendite Online


Freence  2022-01-09 13:59:50 From 127.0.0.1

Purchase Amoxicillin Online No Prescription priligy united states cialis y precio


zersPrott  2022-09-01 15:56:56 From 127.0.0.1

While erectile dysfunction and male enhancement can be embarrassing to talk about during a medical professional s visit, treatment for the condition can dramatically provide improve your quality of life, self confidence and sex life generic cialis no prescription


nealseNus  2022-09-06 00:33:25 From 127.0.0.1

Our bodies are an essential part of our personal lives, and our emotional attachments with others is of equal importance, so we always need to do our part to enhance our sexual abilities buying generic cialis online safe


enjoync  2023-02-18 21:19:40 From 127.0.0.1

Therapy acts to either block the production of oestrogen or the stimulatory action of oestrogen on tumour cells 1 isotretinoin Testosterone or Sustanon can be stacked with a couple of other steroids such as Dianabol, Deca, Anavar, etc


ShePhola  2024-02-26 07:34:27 From 127.0.0.1

glucophage biverkningar