简体   繁体   中英

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.

Thanks in advance and merry christmas!

Your program doesn't work, because you are not passing __pool_input as target but calling it. 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.

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. So best avoid them where you can. There was a similar question recently about async input . Maybe you find something in there you like.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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