gevent:I / O在超时之前完成,但仍然会发生超时

时间:2017-05-04 14:08:25

标签: python timeout gevent

我有两个greenlets。第一个greenlet在启动HTTP请求之前启动7秒超时,我知道这将需要5秒才能完成。第二个greenlet正在执行一些CPU绑定任务(由time.sleep模拟),需要10秒才能完成。代码:

from gevent import monkey; monkey.patch_socket()

import time

import gevent
import requests


def f1():
    try:
        with gevent.Timeout(7):
            print "f1: downloading our page in 5 seconds"
            requests.get('http://httpbin.org/delay/5')
    except gevent.Timeout:
        print "Timed out."
    else:
        print "Finished!"


def f2():
    print "f2: being greedy for 10 seconds"
    time.sleep(10)


if __name__ == '__main__':
    g1 = gevent.spawn(f1)
    g2 = gevent.spawn(f2)
    gevent.joinall([g1, g2])

当我运行此代码时,即使我知道HTTP请求已完成,也会触发超时:

$ python test.py
f1: downloading our page in 5 seconds
f2: being greedy for 10 seconds
Timed out.

time.sleep电话显然是导致超时的原因,但我实际上并不关心这需要多长时间。我真正想要限制的是HTTP请求的持续时间。

是否有任何方法可以编写此代码,以便仅在未执行HTTP请求时才会发生超时?有没有办法在超时事件之前首先处理I / O事件?

1 个答案:

答案 0 :(得分:0)

NB - 阻止调用 - 如CPU绑定函数 - 不应该分配给greenlet,因为根据定义它们会阻止所有其他greenlet运行。

使用gevent.threadpool.ThreadPool提供的本地线程池的组合来阻止任务,使用greenlet来组合非阻塞任务。

示例代码中的行为是因为代码没有修补时间而time.sleep(10)导致gevent超时,因为它阻塞了整个事件循环,这意味着所有的greenlets。

这可以按预期工作:

from gevent import monkey
monkey.patch_all()

import time

import gevent
import requests


def f1():
    try:
        with gevent.Timeout(7):
            print "f1: downloading our page in 5 seconds"
            requests.get('http://httpbin.org/delay/5')
    except gevent.Timeout:
        print "Timed out."
    else:
        print "Finished!"


def f2():
    print "f2: being greedy for 10 seconds"
    time.sleep(10)


if __name__ == '__main__':
    g1 = gevent.spawn(f1)
    g2 = gevent.spawn(f2)
    gevent.joinall([g1, g2])

输出:

f1: downloading our page in 5 seconds
f2: being greedy for 10 seconds
Finished!

还可以使用gevent.sleep来避免修补时间。