python - 可取消的 Asyncio 键盘输入

标签 python python-asyncio

我正在尝试使用 asyncio 编写并发 Python 程序,该程序也接受键盘输入。当我尝试关闭我的程序时出现问题。由于键盘输入最终是通过 sys.stdin.readline 完成的,该函数仅在我按下 ENTER 后返回,无论我是否 stop() 事件循环或 cancel() 函数的 Future

有什么方法可以提供可以取消的asyncio键盘输入吗?

这是我的 MWE。它将接受键盘输入 1 秒,然后 stop():

import asyncio
import sys

async def console_input_loop():
    while True:
        inp = await loop.run_in_executor(None, sys.stdin.readline)
        print(f"[{inp.strip()}]")

async def sleeper():
    await asyncio.sleep(1)
    print("stop")
    loop.stop()

loop = asyncio.get_event_loop()
loop.create_task(console_input_loop())
loop.create_task(sleeper())
loop.run_forever()

最佳答案

问题在于执行者坚持确保在程序终止时所有正在运行的 future 都已完成。但在这种情况下,您实际上想要一个“不干净”的终止,因为没有可移植的方法来取消正在进行的 read() 或异步访问 sys.stdin

取消 future 没有效果,因为 concurrent.futures.Future.cancel一旦它的回调开始执行,它就是一个空操作。避免不必要的等待的最佳方法是首先避免 run_in_executor 并生成您自己的线程:

async def ainput():
    loop = asyncio.get_event_loop()
    fut = loop.create_future()
    def _run():
        line = sys.stdin.readline()
        loop.call_soon_threadsafe(fut.set_result, line)
    threading.Thread(target=_run, daemon=True).start()
    return await fut

该线程是手动创建的并标记为“守护进程”,因此在程序关闭时没有人会等待它。因此,使用 ainput 而不是 run_in_executor(sys.stdin.readline) 的代码变体按预期终止:

async def console_input_loop():
    while True:
        inp = await ainput()
        print(f"[{inp.strip()}]")

# rest of the program unchanged

关于python - 可取消的 Asyncio 键盘输入,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58493467/

相关文章:

python - Travis 的 Numpy 依赖关系问题

python - 如何在 Ubuntu 上使用 Python 查找 Apache2 的配置错误?

python-3.x - python socket_io.emit() 从函数调用

比异步更快的 Python 同步代码示例

python - 如何重新连接 asyncio 上的套接字?

python - 如何使用Parts-of-Speech来评估语义文本相似度?

python - 使用 requests 和 Beautiful Soup 进行抓取时无法提取描述和评级

sockets - 如何让我的异步客户端调用套接字服务器并等待响应

python - sqs 的异步等待接收消息无法正常工作

python - 为什么我的神经网络显示奇怪的结果?