Python async - 所有 aiohttp 请求立即发送
Python async - all aiohttp request get sent at once
我正在使用 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))
但是我有一个问题,看起来所有的请求都是 'prepared' 一个,然后一次发送。
这是输出的打印方式,其中 "blocking calculation" 在 for "fetch" 函数中:gif1
这就是在 for 循环中完成 "blocking calculation" 的地方:gif2
我有两个问题。
1. 是什么导致了 gif1 和 2 之间的行为差异?
2.为什么所有请求都一次发送?我希望输出类似于此:
开始请求
开始请求
开始请求
完成请求
完成请求
开始请求
完成请求
...
问题在于阻塞代码(例如对 time.sleep(0.3)
的调用)无法由 asyncio 并行执行,因为它会阻塞整个事件循环线程。将其替换为 await asyncio.sleep(0.3)
,问题就会消失。
如果您有必须在协程中 运行 的实际阻塞代码(例如 numpy 计算),请在侧线程中使用 await loop.run_in_executor(None, blocking_function)
到 运行 计算并安全地等待结果,允许其他协程在等待时取得进展。
我正在使用 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))
但是我有一个问题,看起来所有的请求都是 'prepared' 一个,然后一次发送。
这是输出的打印方式,其中 "blocking calculation" 在 for "fetch" 函数中:gif1
这就是在 for 循环中完成 "blocking calculation" 的地方:gif2
我有两个问题。
1. 是什么导致了 gif1 和 2 之间的行为差异?
2.为什么所有请求都一次发送?我希望输出类似于此:
开始请求
开始请求
开始请求
完成请求
完成请求
开始请求
完成请求
...
问题在于阻塞代码(例如对 time.sleep(0.3)
的调用)无法由 asyncio 并行执行,因为它会阻塞整个事件循环线程。将其替换为 await asyncio.sleep(0.3)
,问题就会消失。
如果您有必须在协程中 运行 的实际阻塞代码(例如 numpy 计算),请在侧线程中使用 await loop.run_in_executor(None, blocking_function)
到 运行 计算并安全地等待结果,允许其他协程在等待时取得进展。