2017-05-04 71 views
0

我有两个greenlet。第一个greenlet在启动一个HTTP请求之前启动一个7秒的超时,我知道需要5秒钟才能完成。第二个greenlet正在执行一些CPU约束任务(由time.sleep模拟),需要10秒才能完成。代码:gevent:I/O在超时之前完成,但超时仍然发生

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事件?

回答

0

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

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

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

这按预期工作:

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避免贴敷时间。

+0

我正在使用'time.sleep',因为我试图模拟一个CPU绑定的任务,它确实会阻塞整个事件循环。但是你让我想,也许我不应该在事件循环中做这样的事情 - 可能是'gevent.threadpool'的意思。 – jobo3208

+0

相当。阻塞任务不属于greenlet,因为它们会阻塞整个事件循环。使用阻塞或CPU绑定函数的线程池和非阻塞调用的greenlet的组合。 – danny

相关问题