2017-05-04 37 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

相關問題