【问题标题】:How does 'yield' work in tornado when making an asynchronous call?进行异步调用时,“yield”在龙卷风中如何工作?
【发布时间】:2014-11-14 22:46:30
【问题描述】:

最近在学习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...]

我曾经知道yield是把一个普通函数变成一个生成器的关键词,当它以other = yield foo的形式使用时,意味着“yield foo,当一个值被发送给我时,将 other 设置为该值。” 所以我在 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

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

In [5]: print result
init

然后我调用了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: 

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

In [7]: print result
new message

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

我的问题是:

回到上面显示的代码,按照这个逻辑,

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

当方法client.fetch 返回时,将创建一个Task 实例并将yield 发送给调用者,但左侧的变量response 将不会收到任何信息,因为没有执行send() 方法。我对此感到很困惑,并且徒劳无功。

非常感谢您的解释!

【问题讨论】:

  • client.fetch 未被调用;它只是被引用Task() 对象将负责实际调用它。
  • 您认为 Tornado 不会在您的生成器上使用 send() 的原因是什么?
  • 这里的client是什么,是tornado.httpclient.AsyncHTTPClient的实例吗?

标签: python asynchronous generator tornado yield


【解决方案1】:

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

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

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

然后 Tornado 将运行 Task; Task 将依次调用 client.fetch() 并使用提供的参数,加上一个回调函数client.fetch() 然后异步运行,并调用回调。然后将传递给回调的任何内容记录为Task 结果。

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

换句话说,Tornado 确实在此处使用.send(),并且将某些东西分配给response

【讨论】:

    【解决方案2】:

    它有点意思是“我把控制权交给你;当你得到这个 Future 的结果时回来”,因此有点像异步解引用运算符。 Tornado 通过send在结果准备就绪时回复结果。

    请参阅http://tornado.readthedocs.org/en/latest/gen.html 以获得更深入的解释。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-07-30
      • 1970-01-01
      • 1970-01-01
      • 2018-12-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多