asyncio聊天客户端使用aioconsole的实现难点:input()与asyncio不兼容
异步输入实现方案
以下两种方案均适配最新版asyncio,无需依赖aioconsole:
方案1:Python 3.9+ 原生实现(推荐)
通过asyncio.to_thread将同步input()包装为异步调用,无需额外安装依赖,代码最简:
async def asynchronous_input(prompt: str = "") -> str: return await asyncio.to_thread(input, prompt)
方案2:兼容Python 3.7/3.8 版本实现
如果运行环境Python版本低于3.9,使用线程池执行器实现:
import concurrent.futures # 单例线程池,避免重复创建开销 _input_executor = concurrent.futures.ThreadPoolExecutor(max_workers=1) async def asynchronous_input(prompt: str = "") -> str: loop = asyncio.get_running_loop() return await loop.run_in_executor(_input_executor, input, prompt)
原有代码修正
现有代码中存在协程无法并行的问题:chat_client函数内按顺序await message_sender和await message_reciever会导致message_sender的死循环永远阻塞接收逻辑,需要修改为并行运行:
async def chat_client(): reader, writer = await asyncio.open_connection("xxx.xxx.xxx.xxx", xxx) # 同时启动收发两个协程 await asyncio.gather( message_sender(writer), message_reciever(reader) )
最终message_sender函数修改
替换占位的异步输入调用即可:
async def message_sender(writer): try: while True: # 可自定义输入提示符,比如改成"你: " message = await asynchronous_input("") await message_writer(message, writer) except asyncio.TimeoutError: print("----------- You lost your connection -----------") writer.close() await writer.wait_closed() quit()
完整修改后代码示例
import asyncio import struct import concurrent.futures # 兼容全版本的异步输入实现 _input_executor = concurrent.futures.ThreadPoolExecutor(max_workers=1) async def asynchronous_input(prompt: str = "") -> str: loop = asyncio.get_running_loop() return await loop.run_in_executor(_input_executor, input, prompt) async def chat_client(): reader, writer = await asyncio.open_connection("xxx.xxx.xxx.xxx", xxx) await asyncio.gather( message_sender(writer), message_reciever(reader) ) async def message_sender(writer): try: while True: message = await asynchronous_input("你: ") await message_writer(message, writer) except asyncio.TimeoutError: print("----------- You lost your connection -----------") writer.close() await writer.wait_closed() quit() async def message_reciever(reader): while True: size, = struct.unpack('<L', await reader.readexactly(4)) rcv_message = await reader.readexactly(size) # 打印收到的消息时添加前缀区分 print(f"\n对方: {rcv_message.decode()}\n你: ", end="") async def message_writer(message, writer): data = message.encode() writer.write(struct.pack('<L', len(data))) writer.write(data) await writer.drain() try: asyncio.run(chat_client()) except KeyboardInterrupt: print("\n----------- You left the Chat. -----------") quit()
内容的提问来源于stack exchange,提问作者SoccerFan
相关产品推荐
相关产品推荐

