Posted on 2014-01-22 12:35:42 gevent
除非有隐式或者显示的手段switch到这个greenlet。
只是创建了一个greenlet实例,并加入到了greenlet链,还没有运行它。
greenlet.switch最终会调用greenlet.c中的C函数。 greenlet.c中g_swith会扫描greenlet链,如果发现没有启动的greenlet,则调用g_initialstub启动它。 实际上g_initialstub会在greenlet类实例中查找run属性,找到了则运行它。 如果greenlet是已经启动的,则switch到main hub.
按照3的说法,它首先创建了greenlet实例,设置了实例的’run’属性。 然后直接运行刚才指定的’run’属性,也可以叫它callback,是一个callable对象。
最后再启动一个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’字符串之后,进程退出。
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()返回最终的值。
结合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))
首先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'>
That’s a weluoth-lght-out answer to a challenging question
Keflex Dose For Dog
hydroxychloroquine for sale online
Kamagra Vendite Online
Purchase Amoxicillin Online No Prescription priligy united states cialis y precio
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
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
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