使用await或yield迭代循环会导致错误

时间:2016-09-01 19:02:50

标签: python python-3.x asynchronous tornado coroutine

我来自Twisted / Klein。我安静地来,并要求Tornado帮助。我正在调查龙卷风以及它对异步的看法与Twisted的区别。 Twisted有类似于gen.coroutine的{​​{3}},我可以像这样编写异步代码:

kleinsample.py

@app.route('/endpoint/<int:n>')
@defer.inlineCallbacks
def myRoute(request, n):
    jsonlist = []
    for i in range(n):
        yield jsonlist.append({'id': i})
    return json.dumps(jsonlist)

curl cmd:

curl localhost:9000/json/2000

此端点将创建一个n个元素的JSON字符串。 n可能很小或很大。我能够在Twisted中将其分解,以便事件循环不会使用yield阻止。现在,我试图将其转换为龙卷风:

tornadosample.py

async def get(self, n):
    jsonlist = []
    for i in range(n):
        await gen.Task(jsonlist.append, {'id': i})    # exception here
    self.write(json.dumps(jsonlist))

追溯:

 TypeError: append() takes no keyword arguments

我很困惑我应该做些什么来正确迭代循环中的每个元素,以便事件循环不被阻止。有没有人知道“龙卷风”的做法?

3 个答案:

答案 0 :(得分:1)

您不能也不能等待jobs,因为它不是协程并且不会返回Future。如果你想偶尔屈服以允许其他协同程序继续使用Tornado的事件循环,等待gen.moment

append

那就是说,除非这个功能非常 CPU密集型并且需要几百毫秒或更长时间才能完成,你可能最好不要一次完成所有计算而不是多次通过函数返回之前的事件循环。

答案 1 :(得分:1)

list.append()会返回None,因此您的Klein示例看起来像是会产生一些对象,这有点误导。这相当于jsonlist.append(...); yield两个单独的语句。龙卷风相当于await gen.moment代替裸yield

另请注意,在Tornado中,处理程序通过调用self.write()而不是返回值来生成响应,因此return语句应为self.write(json.dumps(jsonlist))

答案 2 :(得分:0)

让我们看看gen.Task docs

  

调整基于回调的异步函数以在协同程序中使用。

     

使用一个函数(和可选的附加参数)并使用那些参数加上一个回调关键字参数来运行它。传递给回调的参数作为yield表达式的结果返回。

由于append不接受关键字参数,因此它不知道如何处理该callback kwarg并吐出该异常。

你能做的就是用你自己的函数包裹append来接受callback kwarg或this回答中显示的方法。