python3.5async for块ioloop

2024-04-24 12:42:07 发布

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

我有一个简单的aiohttp服务器,有两个处理程序。 第一个在async for循环中进行一些计算。第二个只返回文本响应。not_so_long_operation使用最慢的递归实现返回第30个fibonacci数,大约需要1秒的时间。在

def not_so_long_operation():
    return fib(30)

class arange:
    def __init__(self, n):
        self.n = n
        self.i = 0

    async def __aiter__(self):
        return self

    async def __anext__(self):
        i = self.i
        self.i += 1
        if self.i <= self.n:
            return i
        else:
            raise StopAsyncIteration

# GET /
async def index(request):
    print('request!')
    l = []
    async for i in arange(20):
        print(i)
        l.append(not_so_long_operation())

    return aiohttp.web.Response(text='%d\n' % l[0])

# GET /lol/
async def lol(request):
    print('request!')
    return aiohttp.web.Response(text='just respond\n')

当我试图获取/然后/lol/时,只有当第一个完成时,它才会对第二个进行响应。
我做错了什么?如何让索引处理程序在每次迭代时释放ioloop?在


Tags: self处理程序forasyncreturnsoaiohttprequest
3条回答

您的示例没有用于在任务之间切换的屈服点await语句)。 异步迭代器允许__aiter__/__anext__内使用await,但不自动将其插入代码中。在

class arange:
    def __init__(self, n):
        self.n = n
        self.i = 0

    async def __aiter__(self):
        return self

    async def __anext__(self):
        i = self.i
        self.i += 1
        if self.i <= self.n:
            await asyncio.sleep(0)  # insert yield point
            return i
        else:
            raise StopAsyncIteration

应该像你期望的那样工作。在

在实际应用程序中,您很可能不需要await asyncio.sleep(0)调用,因为您将等待数据库访问和类似的活动。在

这里并不需要异步迭代器。相反,您可以简单地将控件返回到循环中的事件循环。在Python3.4中,这是通过使用一个简单的yield来完成的:

@asyncio.coroutine
def index(self):
    for i in range(20):
        not_so_long_operation()
        yield

在Python3.5中,您可以定义一个Empty对象,该对象的作用基本相同:

^{pr2}$

然后使用await语法:

async def index(request):
    for i in range(20):
        not_so_long_operation()
        await Empty()

或者简单地使用asyncio.sleep(0),即recently optimized

async def index(request):
    for i in range(20):
        not_so_long_operation()
        await asyncio.sleep(0)

也可以使用default executor在线程中运行not_so_long_operation

async def index(request, loop):
    for i in range(20):
        await loop.run_in_executor(None, not_so_long_operation)

由于fib(30)受CPU限制并且共享很少的数据,您可能应该使用^{}(而不是ThreadPoolExecutor):

async def index(request):
    loop = request.app.loop
    executor = request.app["executor"]
    result = await loop.run_in_executor(executor, fib, 30)
    return web.Response(text="%d" % result)

创建executor时设置executor

^{pr2}$

相关问题 更多 >