I'm stuck here a little bit with surely a simple thing. Briefly about the problem:
- connected asyncio
- Created 2 async user_io and task_manager cortices
- In user_io () there is an input that is completely ignored by await
- task_manager () is executed only after the completion of user_io ()
Attention question - How to make waiting for input and other korutiny "parallel"?
Thanks for the help!

# Π–Π΄Ρ‘Ρ‚ ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΡΠΊΠΈΠΉ Π²Π²ΠΎΠ΄ async def user_io(): try: # Π–Π΄Ρ‘ΠΌ дСйствия ΠΎΡ‚ ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»Ρ while True: # Await, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ Π½ΠΈΠΆΠ΅ Π½Π΅ Ρ€Π°Π±ΠΎΡ‚Π°Π΅Ρ‚! command = await input('Π’Π²Π΅Π΄ΠΈΡ‚Π΅ ΠΊΠΎΠΌΠ°Π½Π΄Ρƒ (Π‘ to EXIT): ') if re.match(r'[cC]', command): break except KeyboardInterrupt: print('Π‘ΠΊΡ€ΠΈΠΏΡ‚ остановлСн ΠΏΠΎ ΠΊΠΎΠΌΠ±ΠΈΠ½Π°Ρ†ΠΈΠΈ клавиш') # ΠšΠΎΡ€ΡƒΡ‚ΠΈΠ½Π°, выполняСмая ΠΏΠ°Ρ€Π°Π»Π»Π΅Π»ΡŒΠ½ΠΎ с ΠΎΠΆΠΈΠ΄Π°Π½ΠΈΠ΅ΠΌ ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΡΠΊΠΎΠ³ΠΎ Π²Π²ΠΎΠ΄Π° async def task_manager(): await asyncio.sleep(1) print("I'm a task manager 1!") await asyncio.sleep(1) print("I'm a task manager 2!") if __name__=="__main__": # ЗапускаСм Ρ†ΠΈΠΊΠ» событий loop = asyncio.get_event_loop() tasks = [ loop.create_task(user_io()), loop.create_task(task_manager()) ] loop.run_until_complete(asyncio.wait(tasks)) loop.close() sys.exit() 

1 answer 1

input() is a blocking function. Calling blocking functions in asynchronous code blocks the event loop. Therefore, they must be run in a separate thread. Yes, and the interruption from the keyboard you do not catch in the asynchronous code. In an amicable way, you need to assign a handler by calling the add_signal_handler () method, but this does not work on Windows.

 import asyncio import signal def shutdown(): # ΠžΡ‚ΠΌΠ΅Π½ΡΠ΅ΠΌ всС Π·Π°Π΄Π°Ρ‡ΠΈ, ΠΊΡ€ΠΎΠΌΠ΅ Π²Ρ‹Π·Π²Π°Π²ΡˆΠ΅ΠΉ for task in asyncio.Task.all_tasks(): if task is not asyncio.tasks.Task.current_task(): task.cancel() async def user_io(): loop = asyncio.get_event_loop() # Π–Π΄Ρ‘ΠΌ дСйствия ΠΎΡ‚ ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»Ρ while True: # ЗапускаСм input() Π² ΠΎΡ‚Π΄Π΅Π»ΡŒΠ½ΠΎΠΌ ΠΏΠΎΡ‚ΠΎΠΊΠ΅ ΠΈ ΠΆΠ΄Ρ‘ΠΌ Π΅Π³ΠΎ Π·Π°Π²Π΅Ρ€ΡˆΠ΅Π½ΠΈΡ command = await loop.run_in_executor(None, input, 'Для Π²Ρ‹Ρ…ΠΎΠ΄Π° Π²Π²Π΅Π΄ΠΈΡ‚Π΅ C:\n') if command.lower() == 'c': shutdown() # ΠžΡ‚ΠΌΠ΅Π½ΡΠ΅ΠΌ всС Π·Π°Π΄Π°Ρ‡ΠΈ break # ΠΈ Π²Ρ‹Ρ…ΠΎΠ΄ΠΈΠΌ ΠΈΠ· Ρ†ΠΈΠΊΠ»Π° # Π‘ΠΎΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΠ°, выполняСмая ΠΏΠ°Ρ€Π°Π»Π»Π΅Π»ΡŒΠ½ΠΎ с ΠΎΠΆΠΈΠ΄Π°Π½ΠΈΠ΅ΠΌ ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΡΠΊΠΎΠ³ΠΎ Π²Π²ΠΎΠ΄Π° async def task_manager(): counter = 0 while True: try: await asyncio.sleep(1) except asyncio.CancelledError: break # Π’Ρ‹Ρ…ΠΎΠ΄ΠΈΠΌ ΠΈΠ· Ρ†ΠΈΠΊΠ»Π°, Ссли Π·Π°Π΄Π°Ρ‡Ρƒ ΠΎΡ‚ΠΌΠ΅Π½ΠΈΠ»ΠΈ counter += 1 print("I'm a task manager {}!".format(counter)) if __name__ == '__main__': # УстанавливаСм ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊ Ctrl+C signal.signal(signal.SIGINT, lambda n, f: shutdown()) # ЗапускаСм Ρ†ΠΈΠΊΠ» событий loop = asyncio.get_event_loop() # Π—Π°Π΄Π°Ρ‡Π° Тдущая Π·Π°Π²Π΅Ρ€ΡˆΠ΅Π½ΠΈΡ сопрограм user_io ΠΈ task_manager main_task = asyncio.wait([user_io(), task_manager()]) try: loop.run_until_complete(main_task) except asyncio.CancelledError: # ПозволяСм main_task Π·Π°Π²Π΅Ρ€ΡˆΠΈΡ‚ΡŒΡΡ loop.run_until_complete(main_task) loop.close() 
  • as it is all difficult. Why not already use real streams? - Andrio Skur
  • @AndrioSkur firstly, specifically in Python, getting the benefit of using threads is even harder because of GIL. Secondly, threads consume significantly more resources than a cycle of events. Thirdly, writing stable multi-threaded code is much more difficult. They are waiting for the race, deadlocks, violation of invariants and other pain. Finally, as Alan Cox said, streaming is necessary for those who cannot program finite automata :) - Sergey Gornostaev
  • 1- your code already uses (default executor) 2- when waiting for GIL input, usually 3 words are automatically released about situations in which such hacks are useful when shutting down, for future readers - jfs
  • 1 - Uses, but only as a door to a synchronous world. Sometimes you can't do without it. Fortunately, rarely. 3 - Are you run_until_complete about canceling tasks and re-calling run_until_complete ? Just one of the ways to stop tasks that are in an infinite loop and complete the work of the event loop so that it does not curse on unhandled exceptions and unfinished futures. - Sergey Gornostaev
  • @SergeyGornostaev Thank you so much! This decision suited me. - Alex Y.