我在将 asyncio 集成到较旧的代码库中时遇到了麻烦。其中大部分是可以管理的,但我遇到了非异步函数需要调用协程的麻烦。这似乎可以通过在相关协程上运行loop.run_until_complete()来最容易地完成。当这种情况发生在调用堆栈的顶部时(即,当我们可以保证循环尚未运行时),它工作得很好 - 协程可以调用任何其他协程。我遇到麻烦的是我们无法保证循环尚未运行。下面的(诚然有些人为的)代码说明了这一点:
import asyncio
import aioredis
from asyncio_extras import (
contextmanager as async_contextmanager)
async def is_flag_set(redis_pool, key):
async with acquire_redis_connection(redis_pool) as redis_connection:
return await redis_connection.get(key)
###
async def helper_1():
pool = await create_redis_pool()
return await is_flag_set(pool, 'my_key')
def test_1():
loop = asyncio.get_event_loop()
return loop.run_until_complete(
helper_1())
###
def helper_2(pool=None):
loop = asyncio.get_event_loop()
if pool is None:
pool = loop.run_until_complete(create_redis_pool(
db_number=0))
return loop.run_until_complete(is_flag_set(pool, 'my_key'))
def test_2():
return helper_2()
###
async def helper_3(db_number):
pool = await create_redis_pool(
db_number=db_number)
return helper_2() …Run Code Online (Sandbox Code Playgroud) 我有一个带有 HTTP 端点的 aiohttp (3.4.4) 服务器,该端点将文件作为输入(客户端发出多部分表单 POST)。我有一个测试客户端,可以向端点发送 10K POST。服务器端点如下所示:
async def event_handler(request):
files = await request.post()
file_field = files['file_from_client']
file_contents = file_field.file.read()
Run Code Online (Sandbox Code Playgroud)
间歇性地,当我的端点尝试查看 POST 有效负载中提供的文件时,我收到以下异常:
"~/venv/python3.7/site-packages/aiohttp/web_protocol.py", line 390, in start
"~/venv/python3.7/site-packages/aiohttp/web_app.py", line 366, in _handle
"~/projects/my_project/controllers.py", line 58, in event_handler
"~/venv/python3.7/site-packages/aiohttp/web_request.py", line 585, in post
"~/venv/python3.7/tempfile.py", line 618, in TemporaryFile
"~/venv/python3.7/tempfile.py", line 258, in _mkstemp_inner
OSError: [Errno 24] Too many open files: '/tmp/tmpjnt4eu_k'
Run Code Online (Sandbox Code Playgroud)
(注意:event_handler 的第 58 行是“await request.post()”行)
我知道是什么原因造成的。我的进程的文件描述符限制设置为默认值 1024,并且我的客户端在我的服务器上抛出了足够多的请求,以至于超出了该限制。我的问题是我不确定最好的服务器缓解是什么。
这篇文章提到了这个问题,有两种可能的解决方案:增加服务端进程的文件描述符数量,或者在客户端引入一个信号量来保证很多请求永远不会被发送到服务端。后者对于测试问题都很好,但我不控制生产中的客户端。前者很容易完成,并减轻了这个特定问题,但它似乎只是提高了天花板 - 有足够的请求,似乎仍然会发生这个问题。
是否可以对 aiohttp 服务器尝试一次处理的请求数量进行限制,并让其他服务器排队等待?