【问题标题】:How to have a comfortable (e.g. GNU-readline style) input line in an asyncio task?如何在异步任务中拥有舒适的(例如 GNU-readline 样式)输入行?
【发布时间】:2022-01-07 21:15:34
【问题描述】:

我有一个包含两个任务的异步程序:

  • 任务 1 做了一些工作
  • task 2 提供了一个命令行界面 (CLI),它从用户那里读取命令并将它们发送给 task 1 进行处理

CLI 基本上是一个从连接到标准输入的异步流中读取行的循环。

它有效,但不是很舒服。问题是输入行没有提供除[BACKSPACE ctrl-H] 和[ctrl-U] 之外的编辑命令,它们是在Linux 终端级别而不是在程序中处理的。我至少想要 [LEFT] 和 [RIGHT] 箭头以及 [DEL]。

我尝试了内置 input() 和 readline 导入,这给了我一个舒适的编辑,但它必须在单独的线程中运行,因为它是阻塞的 (loop.run_in_executor)。

现在问题是 [ctrl-C] 处理 (KeyboardInterrupt)。任务被取消,但input() 在它自己的线程中仍然等待[ENTER] 键。只有在 [ENTER] 后,应用程序才会退出。这太令人困惑了,对于这种方法来说,它是一个“阻止程序错误”。不幸的是,不可能杀死一个线程,所以我无法使 [ctrl-C] 按键正常终止程序。

您知道如何解决input() 的问题,或者您知道如何在异步任务中启用基本输入行编辑的另一种方法?

【问题讨论】:

  • @furas prompt-toolkit 看起来有大量的特性和比我需要的更多的功能,但它有一个异步接口,所以绝对是我应该测试的东西。谢谢你的提示。
  • 我只是偶然偶然发现了你的问题:(stackoverflow.com/q/58454190/14412190)。这可能很有趣。
  • 我在没有阅读文档的情况下快速尝试aioconsole.ainput,但没有编辑功能。

标签: python python-asyncio readline


【解决方案1】:

您是否考虑过将input 部分保留在主线程中并在子线程中运行事件循环? 这可能有点老套,肯定需要改进,但你可以使用你所拥有的:

import asyncio
from threading import Thread

streaming_queue = asyncio.Queue()


async def main_async():
    while True:
        chunk = await streaming_queue.get()
        print("got chunk: ", chunk)


def event_loop(loop):
    try:
        loop.run_until_complete(main_async())
    except asyncio.CancelledError:
        loop.close()
        print("loop closed")


def send_chunk(chunk):
    streaming_queue.put_nowait(chunk)


def cancel_all():
    for task in asyncio.all_tasks():
        task.cancel()


if __name__ == "__main__":
    loop = asyncio.get_event_loop()
    event_thread = Thread(target=event_loop, args=(loop,))
    event_thread.start()
    try:
        while True:
            chunk = input()
            loop.call_soon_threadsafe(send_chunk, chunk)
    except KeyboardInterrupt:
        print("cancelling all tasks")
        loop.call_soon_threadsafe(cancel_all)
        print("joining thread")
        event_thread.join()
        print("done")

最好的当然是input 的异步实现。不确定是否有类似的东西,或者@furas 的链接是否有可能......

【讨论】:

  • 我刚刚意识到“prompt-toolkit”是一个单独的项目并实现了一个异步 API。在第一次单击@furas 链接时,我只看到了 REPL 的东西......我让我的答案站在那里,因为它是一种没有任何进一步依赖关系的解决方法,但 prompt-toolkit 似乎是更好的选择。
  • 很有趣,并且 +1 用于概念证明,但我害怕对项目做出如此大的改变。破坏某物的机会很高,例如信号被传递到主线程。
  • 可以理解。无论如何,感谢您的支持!
猜你喜欢
  • 2010-12-03
  • 2012-03-07
  • 2019-12-20
  • 1970-01-01
  • 2023-02-26
  • 1970-01-01
  • 2017-11-10
  • 1970-01-01
  • 2010-09-14
相关资源
最近更新 更多