【问题标题】:How can gevent.sleep() be canceled?gevent.sleep() 怎么取消?
【发布时间】:2023-01-31 00:30:00
【问题描述】:

我有一个 greenlet,它执行一些 I/O 并计算出睡眠多长时间,直到它应该被唤醒以继续。假设一些外部事件应该导致睡眠中的小绿叶立即醒来并在睡眠后继续。我怎样才能做到这一点?

一个解决方案是杀死 greenlet 并创建一个新的,但这看起来很乱。我尝试过的另一个解决方案是 gevent.wait,超时值为 0、0.1 等。这根本没有做任何事情,而且看起来也很乱。

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()

【问题讨论】:

    标签: python gevent


    【解决方案1】:

    诀窍是注意 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')
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-12-04
      • 1970-01-01
      • 1970-01-01
      • 2014-01-17
      • 2021-05-11
      • 2021-06-26
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多