[英]How can gevent.sleep() be canceled?
我有一個 greenlet,它執行一些 I/O 並計算出睡眠多長時間,直到它應該被喚醒以繼續。 假設一些外部事件應該導致睡眠中的小綠葉立即醒來並在睡眠后繼續。 我怎樣才能做到這一點?
一個解決方案是殺死 greenlet 並創建一個新的,但這看起來很亂。 我嘗試過的另一個解決方案是超時為gevent.wait
等的 gevent.wait。這根本沒有做任何事情,而且看起來也很亂。
import gevent
import gevent.monkey
gevent.monkey.patch_all()
import time
class G(gevent.Greenlet):
def _run(self):
t = self._determine_how_long_to_sleep()
print(f'in run, will sleep for {t}s')
start = time.time()
# how do I make this cancel-able?
gevent.sleep(t)
end = time.time()
# should get here within 1s of canceling the sleep
assert end - start < t + 1
print('success')
def _determine_how_long_to_sleep(self):
"it's not important how we get this number or why"
return 5
g = G()
g.start()
gevent.sleep(1)
# Sure, this works, but not ideal.
g.kill()
g = G()
g.start()
# Does nothing whatsoever:
#gevent.wait(objects=[g], timeout=0.2)
g.join()
訣竅是注意 gevent.Greenlet 是 greenlet.greenlet 的子類,它有一個可以捕獲的throw
方法:
import gevent.monkey
gevent.monkey.patch_all()
import gevent
import time
class InterruptedException(Exception):
pass
class G(gevent.Greenlet):
def _run(self):
t = 5
start = time.time()
try: gevent.sleep(t)
except InterruptedException: pass
end = time.time()
print(f'slept for ~{end-start}s')
assert end - start < t + 1
g = G()
g.start()
gevent.sleep(0)
try:
g.throw(InterruptedException)
except gevent.exceptions.LoopExit:
# There are no other greenlets to switch to so we get this error.
pass
gevent 文檔說要避免使用 greenlet.throw 並更喜歡更高級別的抽象,如 gevent.event.Event。 在我的例子中,可以通過這種方法實現可以取消的睡眠。 將知道必須取消 greenlet 的邏輯移動到在 gevent.event.Event 上調用set
。 好的!
import gevent.monkey
gevent.monkey.patch_all()
import gevent
import gevent.event
import time
ev = gevent.event.Event()
class InterruptedException(Exception):
pass
class G(gevent.Greenlet):
def _run(self):
print('will wait for event')
ev.wait()
print('done waiting for event')
g = G()
g.start()
gevent.sleep(2)
ev.set()
print('after event set')
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.