简体   繁体   English

Python 在异步上下文中对标准输入进行非阻塞读取

[英]Python non blocking read on stdin in an asynchronous context

I'm new to multithreading and I'm trying to build a script that runs asynchronously while having a start/stop mechanism based on user input from stdin.我是多线程的新手,我正在尝试构建一个异步运行的脚本,同时具有基于标准输入的用户输入的启动/停止机制。

I created two threads, one for the asynchronous work and one for reading from stdin.我创建了两个线程,一个用于异步工作,一个用于从标准输入读取。 My idea is that the program runs until the user types "stop" in stdin, and the asynchronous tasks wait until the user types "start" in stdin.我的想法是程序一直运行,直到用户在标准输入中键入“停止”,而异步任务等到用户在标准输入中输入“开始”。

Here is my current code:这是我当前的代码:

class DataManager(metaclass=Singleton):

    def __init__(self):
        self.flag = threading.Event() 
        self.flag.set()
        
        # Thread for reading user input
        self.pool_thread = threading.Thread(target=self.__pool_input())
        self.pool_thread.daemon = True
        self.pool_thread.start()

    # Method to create thread for asynchronous tasks
    def start(self):
        if self.flag.is_set():
            self.flag.clear()
            self.main_thread = threading.Thread(target=self.__main_wrapper)
            self.main_thread.start()
   
    # Method for reading user stdin
    def __pool_input(self):
        val = input()

        if val == "stop":
            self.stop()

        elif val == "start":
            self.start()

    # Wrapper method to start the event loop and call async context
    def __main_wrapper(self):
        loop = asyncio.new_event_loop()
        asyncio.set_event_loop(loop)
        loop.run_until_complete(self.__main())
        loop.close()

    # Main async loop
    async def __main(self):
        while not self.flag.is_set():
            # Run async stuff
            # ...
            print('Thread is running')
            await asyncio.sleep(5)
     
    # Stop the main async loop on user command   
    def stop(self):
        if not self.flag.is_set():
            self.flag.set()


if __name__ == "__main__":
    data_manager = DataManager()
    data_manager.start()

Expected behavior预期行为

  • Async (main) thread runs on loop异步(主)线程循环运行
  • User types "stop" and async thread stops用户键入“停止”并且异步线程停止
  • User types "start" and async loop runs again用户键入“开始”,异步循环再次运行

Current behavior当前行为

  • Async thread is blocked until user types on stdin异步线程被阻塞,直到用户在标准输入上键入
  • Async thread starts running异步线程开始运行
  • Stdin is blocked while async thread runs异步线程运行时标准输入被阻塞

Besides having to keep the __pool_input thread active in some way (because once it reads the input once the thread ends and I never start it again) i don't know how to make the desired outcome work.除了必须以某种方式保持__pool_input线程处于活动状态(因为一旦它在线程结束时读取输入并且我再也不会启动它)我不知道如何使所需的结果起作用。

Thanks in advance and merry christmas!提前致谢,圣诞快乐!

Your program doesn't work, because you are not passing __pool_input as target but calling it.您的程序不起作用,因为您没有将__pool_input作为target传递,而是调用它。 Use利用

self.pool_thread = threading.Thread(target=self.__pool_input)

and I guess it should work.我想它应该可以工作。 Once.一次。 As you said.如你所说。

You can create an infinite loop in __pool_input() the same was you did in __main_wrapper() to read from stdin again.您可以在__pool_input() __main_wrapper()所做的一样,再次从标准输入中读取。

That being said, I think you should change your design.话虽这么说,我认为你应该改变你的设计。 The great thing about async code is that you don't need threads (for anything I/O) and threading is very hard.异步代码的伟大之处在于您不需要线程(对于任何 I/O)并且线程非常困难。 So best avoid them where you can.所以最好尽可能避免它们。 There was a similar question recently about async input .最近有一个关于异步input的类似问题 Maybe you find something in there you like.也许你在那里找到了你喜欢的东西。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM