Python asyncio and threading

0

I am studying the module asyncio of Python and there is the function run_coroutine_threadsafe which should be run on a thread other than the event loop. Here's my script:

#!usr/bin/python3
# -*- coding: utf-8 -*-

import asyncio
import threading


def target():
    print('Iniciou a thread')
    #asyncio.set_event_loop(None)
    #loop = asyncio.new_event_loop()
    asyncio.run_coroutine_threadsafe(blah(), loop)
    print('Finalizou a thread')


async def blah():
    print('Thread atual:', threading.current_thread().name)


async def main():
    thread = threading.Thread(target=target, args=(), kwargs={}, name='Minha Thread')
    thread.setDaemon(True)
    thread.start()
    thread.join()
    print('finalizou')


if __name__ == '__main__':
    loop = asyncio.get_event_loop()
    try:
        loop.run_until_complete(main())
    finally:
        loop.close()

# Output
Iniciou a thread
Finalizou a thread
finalizando
The problem is that the blah corotine is never invoked by the run_coroutine_threadsafe function but I can not find the reason, I even tried to instantiate a new event loop (as you can see in the commented lines) but not even the script it works. What am I missing?

    
asked by anonymous 15.08.2018 / 02:53

1 answer

1

The problem is that you are calling loop.close() before it has the opportunity to run the blah routine.

The blah routine is scheduled to run in the loop, but the main thread (which has the loop) is stuck in main() ... It has never given control to the loop for it to run other routines, and when main() ends the loop is closed.

For example, putting a 1 second wait before looping out:

...
thread.join()
await asyncio.sleep(1)
print('finalizou')
...

Put this await sleep in main() between join() and print as in the example and will have the result you expect. Because await returns the control to the loop.

Another example is to use an event to signal the end of the program:

import asyncio
import threading

def target(e):
    print('Iniciou a thread')
    asyncio.run_coroutine_threadsafe(blah(e), loop)
    print('Finalizou a thread')

async def blah(e):
    print('Thread atual:', threading.current_thread().name)
    e.set() # sinaliza o final da rotina, autorizando o loop a terminar


async def main():
    e = asyncio.Event()
    thread = threading.Thread(target=target, args=(e,), kwargs={}, name='Minha Thread')
    thread.setDaemon(True)
    thread.start()
    await e.wait() # devolve o controle ao loop e espera que
                   # a rotina sinalize o fim do programa
    print('finalizou')

In this way before we finish the loop, we expect to execute the blah routine using a asyncio.Event() event.

    
15.08.2018 / 20:29