使用await或yield causes迭代循环

2024-05-19 20:12:45 发布

您现在位置:Python中文网/ 问答频道 /正文

我来自Twisted/^{}。我平静地来请求帮助。我在调查龙卷风和它的异步和扭曲的区别。Twisted有类似于gen.coroutine,即^{},我可以编写如下异步代码:

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)

卷曲命令:

^{pr2}$

这个端点将创建一个JSON字符串,其中包含n个元素。n可以很小也可以很大。我可以在Twisted中分解它,这样事件循环就不会使用yield阻塞。现在我试着把它变成龙卷风:

龙卷风样本.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

我不知道该怎么做才能正确地迭代循环中的每个元素,这样事件循环就不会被阻塞。有人知道这种“龙卷风”的方式吗?在


Tags: inpyidjson元素fordef事件
3条回答

让我们来看看gen.Taskdocs

Adapts a callback-based asynchronous function for use in coroutines.

Takes a function (and optional additional arguments) and runs it with those arguments plus a callback keyword argument. The argument passed to the callback is returned as the result of the yield expression.

由于append不接受关键字参数,它不知道如何处理callbackkwarg并抛出该异常。在

您可以使用自己的函数包装append,该函数接受callbackkwarg或{a2}答案中显示的方法。在

list.append()返回None,因此Klein示例看起来像是在生成某个对象,这有点误导性。这相当于jsonlist.append(...); yield作为两个单独的语句。龙卷风的等效物是做await gen.moment来代替裸露的yield。在

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

您不能也不能等待append,因为它不是一个协同程序,也不会返回未来。如果您想偶尔让步以允许其他协同程序使用Tornado的事件循环继续,请等待gen.moment。在

from tornado import gen

async def get(self, n):
    jsonlist = []
    for i in range(n):
        jsonlist.append({'id': i})
        if not i % 1000:  # Yield control for a moment every 1k ops
           await gen.moment
    return json.dumps(jsonlist)

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

相关问题 更多 >