【问题标题】:How to avoid blocking code in python with gevent?如何避免在 python 中使用 gevent 阻塞代码?
【发布时间】:2012-08-20 15:45:36
【问题描述】:

我正在玩 gevent,我试图了解为什么我的代码会阻塞以及如何修复它。

我有一个 greenlets 池,它们每个都与一个 thrift 客户端通信,该客户端从远程 thrift 服务器收集数据。出于练习的目的,thrift 服务器总是需要 > 1s 来返回任何数据。 当我生成 greenlets 并运行 join 时,它们不会并行执行,而是一个接一个地执行。我的理解是,发生这种情况是因为我的代码“阻塞”了,因为当我运行monkey.patch_all() 时,所有greenlets 神奇地并行运行。

那么我如何让代码不阻塞自己而不是猴子修补所有东西而不了解它在做什么?

这里有一个我不明白的例子:

import time

from gevent.pool import Pool

def hello():
    print 'Hello %d' % time.time()
    time.sleep(1) 

def main():
    pool = Pool(5)
    for _ in xrange(5):
        pool.spawn(hello)

    pool.join()

if __name__ == '__main__':
    main()

输出

Hello 1345477112
Hello 1345477113
Hello 1345477114
Hello 1345477115
Hello 1345477116

我知道我可以使用 gevent.sleep,但是如何使用常规 time.sleep 使该功能非阻塞?

谢谢

【问题讨论】:

  • 如果你全部打补丁,time.sleep() 将被 gevent.sleep() 替换。
  • @Ivella,但在我的节俭客户端的情况下,如何在不使用全部猴子补丁的情况下编写它以使其成为非阻塞?

标签: python nonblocking gevent


【解决方案1】:

Greenlet 从不并行运行,它们都共享同一个进程和同一个线程,因此一次最多运行一个。

Greenlet 是绿色的,因为它们是协程(“co”来自于合作),因此甚至不能说它们是并发运行的,因为你需要协调它们的运行。 Gevent 在幕后为您完成大部分工作,并从 libevent(或 libev)知道哪些 greenlets 已准备好运行。根本没有抢占。

在您给出的示例中,time.sleep(2) 将使进程在操作系统内休眠,因此 gevent 的调度程序将无法运行并且无法切换到另一个 greenlet。

所以,关于您的问题:如果您不想修补现有代码,您将不得不手动替换对 gevent 等效项的每个阻塞调用,以便 gevent 可以安排调用 greenlet 并选择另一个运行。

编辑:关于使用 gevent 和节俭而不用猴子修补所有:我不知道它是否值得。

如果要修改(fork)thrift的库,只需要更改文件TSocket.py,并更改:

import socket

到:

from gevent import socket

但是您的 thrift 库将依赖于 gevent,如果您更新 thrift,则需要重新应用补丁。

你也可以继承TSocket,把open()的方法改成使用gevent的socket,用它来代替前者,但对我来说似乎更复杂。

我实际上是在使用 Thrift 和 Gevent,为了简单起见,我选择猴子修补整个事情。

【讨论】:

  • 感谢您的解释。如果我“必须”在没有猴子补丁的情况下使用 time.sleep,可以说“gevent.threadpool”更接近我想要的吗?
  • 实际上,我并没有完全得到你想要的......据我所知,gevent.threadpool 的行为与gevent.pool 几乎相同,但具有模仿的界面Python 的threadpool
  • 您的回复让这一切变得有意义。问题是来自 thrift 客户端的套接字被阻塞,因此需要修补。现在我知道猴子修补整个事情是这样做的,我很高兴使用它:) 谢谢 Ivella
  • 补充:在使用C/C++扩展时,gevent.monkey不起作用。在这种情况下,github.com/douban/greenify 会有所帮助。
猜你喜欢
  • 2017-08-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多