Python异步-一次发送所有aiohttp请求

时间:2018-12-22 13:38:23

标签: python asynchronous python-asyncio aiohttp

我正在使用python 3.7和aiohttp,试图将异步http请求从客户端发送到服务器。 这是服务器代码:

import asyncio
from aiohttp import web


async def hello(request):
    print('Got request')
    await asyncio.sleep(2)
    headers = {"content_type": "text/html"}
    response = web.Response(body='Hello', headers=headers)
    return response

app = web.Application()
app.router.add_route("GET", "/", hello)
web.run_app(app)

这是客户端代码:

import asyncio
from aiohttp import ClientSession
import time


async def fetch(url, session):
    print('Starting request')
    # some blocking calculation
    time.sleep(0.3)
    async with session.get(url) as response:
        print('Finished request')


async def run(r):
    url = "http://localhost:8080"
    tasks = []
    start = time.time()
    async with ClientSession() as session:
        for i in range(r):
            task = asyncio.create_task(fetch(url, session))
            tasks.append(task)

        responses = await asyncio.gather(*tasks)
    print(time.time()-start)

asyncio.run(run(10))

但是我遇到一个问题,看起来所有请求都一次“准备好了”,但是却一次全部发送了。

这是在“获取”功能的{block {3}}

内的“分块计算”处打印输出的方式。

这是在for循环内完成“阻塞计算”的样子:gif1

我有两个问题。
1.是什么导致gif1和2之间的行为不同?
2.为什么所有请求都立即发送?我会期望这样的输出:

开始请求
开始请求
开始请求
完成的请求
完成的请求
开始请求
完成的请求
...

1 个答案:

答案 0 :(得分:2)

问题在于,异步调用无法并行执行阻塞代码,例如对time.sleep(0.3)的调用,因为它会阻塞整个事件循环线程。将其替换为await asyncio.sleep(0.3),问题将消失。

如果您有必须在协程内部运行的实际阻止代码(例如numpy计算),请使用await loop.run_in_executor(None, blocking_function)在边线程中运行计算并安全地等待结果,以允许其他协程在等待中。