我正在使用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.为什么所有请求都立即发送?我会期望这样的输出:
开始请求
开始请求
开始请求
完成的请求
完成的请求
开始请求
完成的请求
...
答案 0 :(得分:2)
问题在于,异步调用无法并行执行阻塞代码,例如对time.sleep(0.3)
的调用,因为它会阻塞整个事件循环线程。将其替换为await asyncio.sleep(0.3)
,问题将消失。
如果您有必须在协程内部运行的实际阻止代码(例如numpy计算),请使用await loop.run_in_executor(None, blocking_function)
在边线程中运行计算并安全地等待结果,以允许其他协程在等待中。