我正在使用同一應用程序內的gevent和龍捲風,以便不支持龍捲風的ioloop的庫可以被制服以使用gevent異步執行。我想我需要運行兩個真正的系統線程,一個專用於Tornado的ioloop,另一個專用於gevent的循環。但是,嘗試調用系統線程內的任何gevent函數將返回not implemented Error
,gevent cannot be used inside threads
。因此,我試圖修補猴子穿爲好,如下面的代碼片段顯示如何在單個應用程序中使用gevent和龍捲風?
from gevent import monkey; monkey.patch_all()
from random import choice
import gevent
import requests
import tornado.ioloop
import tornado.web
import threading
import Queue
q = Queue.Queue()
i = 0
def synchronous_get_url(url, callback=None):
global i
i += 1
d = i
print('bar %d getting %s' % (d, url))
requests.get(url)
print('bar %d finished getting %s' % (d, url))
if callback:
callback()
class GreenEventLoop(threading.Thread):
daemon = True
def run(self):
while True:
url, callback = q.get()
gevent.spawn(synchronous_get_url, url, callback)
繼續...
class MainHandler(tornado.web.RequestHandler):
@tornado.web.asynchronous
def get(self):
print 'Received get request'
urls = [
'http://google.com',
'http://apple.com',
'http://microsoft.com',
'http://github.com',
'http://sourceforge.com',
]
q.put((choice(urls), self._on_fetch), block=False)
self.write("submitted url to queue")
def _on_fetch(self):
print 'Finishing in the handler\n'
try:
self.finish()
except:
pass
# Start GEvent Loop
green_loop = GreenEventLoop()
green_loop.start()
# Start Tornado Loop
application = tornado.web.Application([
(r"/", MainHandler),
], debug=True)
application.listen(7001)
tornado.ioloop.IOLoop.instance().start()
在一個單獨的進程,在命令行中,我運行以下。
from gevent import monkey; monkey.patch_all()
import gevent
import requests
count = 0
def get_stuff(i):
global count
res = requests.get('http://localhost:7000/')
count += 1
print count, res, i
lets = [gevent.spawn(get_stuff, i) for i in range(15)]
gevent.joinall(lets)
這允許同時檢索15個URL,並在接收到響應時返回響應。我不太明白的是爲什麼上面的代碼可以工作。如果線程被gevent修補並轉化爲綠色線程,這意味着一次只能運行一個線程,這意味着雖然gevent不需要獲取新的響應,但龍捲風的ioloop會阻止並不處理新的請求,直到舊的請求回。有人能解釋gevent如何與Tornado的ioloop互動嗎?