如何在Python中持续接收输入并解析它?

ovfsdjhp  于 2023-08-08  发布在  Python
关注(0)|答案(1)|浏览(88)

我想象asyncio能够在后台启动一个进程,而不会阻塞任务的执行流程。毕竟,文档声明asyncio.create_task调度任务的执行,并给出了一个“可靠的‘发射和忘记’后台任务”的示例,它逐个创建和调度任务。
我想使用asyncio来接受输入,并开始解析命令,同时仍然接受进一步的输入。下面是一个简单的例子:

import asyncio
from time import sleep

class Test:
    def __init(self):
        self.calculating = False

    def calculate(self):
        # begin "calculation"
        n = 0
        self.calculating = True
        while self.calculating:
            sleep(1)
            n += 1
            print(n)
        self.calculating = False

    def stop(self):
        # causes calculation to end
        self.calculating = False

    async def parse(self, cmd):
        if cmd == "begin":
            self.calculate()
        elif cmd == "stop":
            self.stop()

async def main():
    t = Test()
    while True:
        cmd = input()
        task = asyncio.create_task(t.parse(cmd))
        await task
        

if __name__ == "__main__":
    asyncio.run(main())

字符串
如果不等待任务,则永远不会解析命令。等待任务确实使“计算”在输入“begin”时开始,正如预期的那样。但是,任务是阻塞的,因此用户永远没有机会输入停止命令。
我看到的asyncio的例子是在运行事件循环之前已知要计算的问题。例如,打开并下载给定的站点列表。这可以通过asyncio.gather方法在一堆任务上完成。但这并不完全是我的情况,我很惊讶没有大量的例子适合我的用例。
我做错了什么?我可能不会按预期使用asyncio吗?或者我使用input()print()是错误的,其他一些替代方案更合适(即:日志记录)?

gudnpqoy

gudnpqoy1#

concurrent.futures.ThreadPoolExecutorthreading.Event计算出来的。

from concurrent.futures import ThreadPoolExecutor
from threading import Event

class Test:
    def __init__(self):
        self.future = 0
    def calculate(self, stop_event):
        # begin "calculation"
        n = 0
        stop_event.clear()
        while True:
            if stop_event.is_set():
                break
            n += 1
            print(n)

    def parse(self, cmd, executor, stop_event):
        if cmd == "begin":
            print("Starting future")
            self.future = executor.submit(self.calculate, stop_event)
        elif cmd == "stop":
            if self.future.running():
                print("Stopping future")
                stop_event.set()
            else:
                print("Future not running")

def main():
    t = Test()
    with ThreadPoolExecutor(max_workers=1) as executor:
        t.future = executor.submit(lambda: None)
        stop_event = Event()
        
        while True:
            cmd = input("Command: ")
            if not cmd:
                continue
            t.parse(cmd, executor, stop_event)
        

if __name__ == "__main__":
    main()

字符串
怪癖:

  • 在Python的IDLE shell中不起作用。
  • input()对话框以某种方式显示在应该跟随它的打印语句之后(即"Stopping future\n{n}\nCommand: ")的最大值

我仍然不完全理解为什么asyncio不适合这个问题,而这个实现是。我很乐意听到任何关于这一点的解释,或者我经历的怪癖。
感谢thomashle的sunfishthe example

相关问题