Python 在TCP客户端是持久的情况下优化简单异步IO程序的方法
使用Python3.7.4和Python 在TCP客户端是持久的情况下优化简单异步IO程序的方法,python,python-3.x,optimization,python-asyncio,python-3.7,Python,Python 3.x,Optimization,Python Asyncio,Python 3.7,使用Python3.7.4和asyncio包,我试图编写一个应用程序,该应用程序将产生大约20000(20k或更多)个TCP客户端,然后连接到一台服务器。 然后,客户端等待来自服务器的命令(received_data=wait reader.read(4096))并继续执行它(wait loop.run_in_executor(…)),然后将响应发送回服务器(writer.write(resp)) 在这个循环完成后,我睡眠100ms(等待asyncio.sleep(100e-3)),以便允许其他
asyncio
包,我试图编写一个应用程序,该应用程序将产生大约20000(20k或更多)个TCP客户端,然后连接到一台服务器。
然后,客户端等待来自服务器的命令(received_data=wait reader.read(4096)
)并继续执行它(wait loop.run_in_executor(…)
),然后将响应发送回服务器(writer.write(resp)
)
在这个循环完成后,我睡眠100ms(等待asyncio.sleep(100e-3)
),以便允许其他协同路由运行。
20k客户端永远不应该断开连接,应该无限期地处理来自服务器的命令
我对如何更改代码以优化它感兴趣(禁止使用uvloop
或直接实现协议
,因为我在uvloop的文档中看到了这可以提高性能),这超出了它现在的能力
假设我无法修改处理请求
例如,await asyncio.sleep(100e-3)
特别困扰我,但我不得不在那里添加它,否则给人的印象是,除了第一个,没有其他协同程序运行!为什么会这样?
假设我取消了睡眠(因为理论上其他wait
s应该允许其他协同程序运行),我还能做什么
下面是我的应用程序的一个简单示例:
import asyncio
from collections import namedtuple
import logging
import os
import sys
logger = logging.getLogger(__name__)
should_exit = asyncio.Event()
def exit(signame, loop):
should_exit.set()
logger.warning('Exiting soon...')
def handle_request(received_data, entity):
logger.info('Backend logic here that consumes a bit of time depending on the entity and the received_data')
async def run_entity(entity, args):
logger.info(f'Running entity {entity}')
loop = asyncio.get_running_loop()
try:
reader, writer = await asyncio.open_connection(args.addr[0], int(args.addr[1]))
logger.debug(f'{entity} connected to {args.addr[0]}:{args.addr[1]}')
try:
while not should_exit.is_set():
received_data = await reader.read(4096)
if received_data:
logger.debug(f'{entity} received data {received_data}')
success, resp = await loop.run_in_executor(None, functools.partial(handle_request, received_data, entity))
if success:
logger.debug(f'{entity} sending response {resp}')
writer.write(resp)
await writer.drain()
await asyncio.sleep(100e-3)
except ConnectionResetError:
pass
except ConnectionRefusedError:
logger.warning(f'Connection refused by {args.addr[0]}:{args.addr[1]}.')
except Exception:
logger.exception('Details of unexpected error:')
logger.info(f'Stopped entity {entity}')
async def main(entities, args):
if os.name == 'posix':
loop = asyncio.get_running_loop()
loop.add_signal_handler(signal.SIGTERM, functools.partial(exit, signal.SIGTERM, loop))
loop.add_signal_handler(signal.SIGINT, functools.partial(exit, signal.SIGINT, loop))
tasks = (run_entity(entity, args) for entity in entities)
await asyncio.gather(*tasks)
if __name__ == '__main__':
ArgsReplacement = namedtuple('ArgsReplacement', ['addr'])
asyncio.run(main(range(20000), ArgsReplacement(addr=['127.0.0.1', '4242'])))