进行异步调用时,龙卷风中的“ yield”如何工作?

str*_*ker 5 python asynchronous yield generator tornado

最近,我正在学习《龙卷风简介》,并且遇到了以下代码:

class IndexHandler(tornado.web.RequestHandler):
    @tornado.web.asynchronous
    @tornado.gen.engine
    def get(self):
        query = self.get_argument('q')
        client = tornado.httpclient.AsyncHTTPClient()
        response = yield tornado.gen.Task(client.fetch,
                "http://search.twitter.com/search.json?" + \
                urllib.urlencode({"q": query, "result_type": "recent", "rpp": 100}))
        body = json.loads(response.body)

        [...omitted the following code...]
Run Code Online (Sandbox Code Playgroud)

我曾经学习过,这yield是将通用函数转换为生成器的关键字,当它以形式使用时,other = yield foo意味着“屈服foo,并且当向我发送值时,将其他值设置为该值”。所以我在ipython中尝试了以下代码:

In [1]: result = 'init'     #set a global variable

In [2]: def test_yield():
   ...:     global result
   ...:     print 'start test...'
   ...:     result = yield 'foo'
   ...:     print 'end test...'
   ...:     

In [3]: t = test_yield()

In [4]: t.next()
start test...
Out[4]: 'foo'  #'foo' has been yield to the caller, and blocked
Run Code Online (Sandbox Code Playgroud)

现在,我打印了全局varialbe result,它仍然引用字符串'init':

In [5]: print result
init
Run Code Online (Sandbox Code Playgroud)

然后我调用了该send()方法,并向发送了一个新字符串yield

In [6]: t.send('new message')
end test...
---------------------------------------------------------------------------
StopIteration                             Traceback (most recent call last)
/home/chiyu/<ipython-input-6-b86312ad7d0e> in <module>()
----> 1 t.send('new message')

StopIteration: 
Run Code Online (Sandbox Code Playgroud)

如预期的那样,StopIteration引发了a 并输出字符串“ end test ...”,但是现在全局变量result已更改:

In [7]: print result
new message
Run Code Online (Sandbox Code Playgroud)

适当地,yield当我们调用该send()方法时,该语句接受了字符串,并将新字符串分配给变量结果。

我的问题是:

回到上面显示的代码,根据此逻辑,

response = yield tornado.gen.Task(client.fetch,
                    "http://search.twitter.com/search.json?" + \
                    urllib.urlencode({"q": query, "result_type": "recent", "rpp": 100}))
Run Code Online (Sandbox Code Playgroud)

当方法client.fetch返回时,Task将创建一个实例并将其创建yield给调用者,但是response左侧的变量将无法接收任何内容,因为没有send()方法被执行。我对此很困惑,徒劳地搜索了。

谢谢您的解释,我将不胜感激!

Vee*_*rac 5

它的意思是“我放弃对你的控制;当你得到这个 Future 的结果时回来”,因此有点像一个异步解引用操作符。Tornado 通过send在准备好时返回结果来做出响应。

有关更深入的解释,请参阅http://tornado.readthedocs.org/en/latest/gen.html


Mar*_*ers 5

已经了解了Tornado如何使用生成器来处理异步调用。

我在这里假设clienttornado.httpclient.AsyncHTTPClient();的一个实例;它的fetch()方法带有回调函数。

tornado.gen.Task对象只需要一对参考client.fetch方法 ; 您当时还没有打电话。您正在Task()使用该方法引用和一个参数构造一个实例,然后产生该实例。

然后龙卷风将会运行Task; 在Task将依次调用client.fetch()所提供的参数,再加上一个回调函数。在client.fetch()随后异步运行,并调用回调函数。然后将传递给回调的所有内容记录为Task结果。

然后将该结果IndexHandler.get()与发送给生成器send(),从yield Task()表达式返回并分配给response

换句话说,龙卷风使用.send()这里的东西分配到response