0

I have a main thread which always needs to be available to read keyboard keypress input.

On each keypress I have to run 4 functions such as displaying, saving to a file, and making an HTTP request etc.

The keypresses can happen quicker than executing the 4 functions.

My logic is the following, but cannot see how I can keep key_press() always running, since I have to await the functions to finish at some point.

async def main():
  async with aiohttp.ClientSession() as client:
  while True:
    pressed_key = key_press() 
    if pressed_key != "":
        f1 = asyncio.create_task(do_something1())
        f2 = asyncio.create_task(do_something2())
        f3 = asyncio.create_task(do_something3())
        f4 = asyncio.create_task(send_to_API())
        
    await f1,f2,f3,send_to_API

asyncio.run(main())
    

Should I try some additional logic, with more loops after calling the asyncio.tasks recursively? Or should I look towards multi-threading, having a thread active running key_press() and the asynchronous calls elsewhere? Any ideas, or hints going towards a good direction?

Kostis4444
  • 45
  • 9
  • Won't the operating system buffer the keystrokes for you? If the user presses the keys too fast for the other functions to keep up, the OS will just hold on to them until you get around to reading them. – Paul Cornelius Oct 24 '20 at 07:38
  • At this stage I am using the keystrokes, but at different phase I will move to USB input from other similar HID devices, so I cannot use the OS buffer. Thanks – Kostis4444 Oct 24 '20 at 17:02
  • I still don't see the problem. The OS has to buffer USB inputs as well. As soon as your application finishes running the four functions, it can react to the next input. Whether the next bit of data has been waiting in an OS buffer or not seems immaterial. Your application can't go any faster than the four functions will allow, so it must wait for the next input in any case. Are you worried that the OS will throw data away before you can read it? – Paul Cornelius Oct 25 '20 at 02:36

1 Answers1

3

If you are trying to simulate USB data stream with the help of input (key_press function in your example), you have to use multithreading module, since input is a blocking function and it will stop asyncio loop work in the thread. To combine asyncio with input function you'll have to use another thread, please find the following example:

import asyncio
import threading


async def do_work(i):
    """take input key and do some work with the input"""
    await asyncio.sleep(5)
    print(i)


async def main_thread_loop_work(_key):
    """simulate multiple tasks caused by key input"""
    t1 = asyncio.create_task(do_work(_key))
    t2 = asyncio.create_task(do_work(_key))
    t3 = asyncio.create_task(do_work(_key))
    await t1
    await t2
    await t3


def thead_worker(_key):
    """target function for another thread"""
    asyncio.run(main_thread_loop_work(_key))


if __name__ == '__main__':
    while True:
        some_key = input("Please provide any key: ")
        th = threading.Thread(target=thead_worker, args=(some_key, ))
        th.start()
Artiom Kozyrev
  • 3,526
  • 2
  • 13
  • 31