我正在尝试使用Pycurl和Gevent来执行HTTP上传。为此,我依赖于geventcurl.py模块,该模块改变了libcurl的 Multi API以使用Gevent的事件循环。
问题在于 READFUNCTION 回调。此回调在 HUB 上下文中执行,因此我们不能 wait(),但此回调必须返回要上传的数据,在我的情况下,此数据来自阻塞源。
以下是一段演示此问题的代码:
#!/usr/bin/env python
from gevent import monkey; monkey.patch_all()
import gevent
from gevent.queue import Queue
import pycurl
from geventcurl import Curl
URL = 'http://localhost:8000/'
class QueueReader:
def __init__(self, q):
self.q = q
def read_callback(self, size):
return self.q.get(timeout=10)
dataq = Queue(10)
c = Curl()
c.setopt(pycurl.URL, URL)
c.setopt(pycurl.UPLOAD, 1)
c.setopt(pycurl.READFUNCTION, QueueReader(dataq).read_callback)
# Start transfer
g = gevent.spawn(c.perform)
for i in xrange(10):
dataq.put(str(i))
gevent.sleep(1)
g.join()
c.close()
要运行代码段,您只需要在localhost:8000上监听,nc -l 8000
即可。会发生什么,因为read_callback()
在HUB上下文中执行,它不会等待,如果队列为空,它将立即引发Empy异常。使用AsyncResult也没有用,因为我们必须wait()才能得到结果。
有没有办法从事件循环回调中的可能阻塞源获取数据?
答案 0 :(得分:0)
如果你摆脱timeout=10
,它将等待来自阻止源的数据。 (参见:http://www.gevent.org/gevent.queue.html,默认行为。)
如果read_callback()的阻塞会干扰for i in xrange(10)
循环的操作,那么通过例如gevent.spawn()
将该循环放入其自己的greenlet中。
另请注意,默认情况下put()
将阻止队列已满。请考虑put_nowait()
,put(timeout=...)
或put(block=False)
来更改默认行为。