28

I have the following code:

async some_callback(args):
    await some_function()

and I need to give it to a Thread as a target:

_thread = threading.Thread(target=some_callback, args=("some text"))
_thread.start()

The error that I get is "some_callback is never awaited".
Any ideas how can I solve this problem?

Damian-Teodor Beleș
  • 864
  • 3
  • 12
  • 26

3 Answers3

38

You can do it by adding function between to execute async:

async def some_callback(args):
    await some_function()

def between_callback(args):
    loop = asyncio.new_event_loop()
    asyncio.set_event_loop(loop)

    loop.run_until_complete(some_callback(args))
    loop.close()

_thread = threading.Thread(target=between_callback, args=("some text"))
_thread.start()

norbeq
  • 2,545
  • 1
  • 13
  • 19
36

As of Python 3.7, you can use asyncio.run() which is a bit more straightforward than loop.run_until_complete():

_thread = threading.Thread(target=asyncio.run, args=(some_callback("some text"),))
_thread.start()
mckbrd
  • 539
  • 7
  • 11
  • How does this actually launch something in a thread? It looked strange to me, and then I tested it and the `some_callback` does indeed execute *before* you start the thread, like it looks like it is going to. You know, because you are calling a sync function and all. No? – AntonOfTheWoods Dec 05 '20 at 07:57
  • 3
    @anton Not sure to understand the question. `some_callback("some_text")` returns a coroutine object, see [the doc](https://docs.python.org/3/library/asyncio-task.html#coroutines): "simply calling a coroutine will not schedule it to be executed" and "To actually run a coroutine, asyncio provides three main mechanisms", among which `asyncio.run`. In my answer, `asyncio.run` is the target of the thread and takes the coroutine object returned by the `some_callback` function as argument, it is therefore executed in the thread – mckbrd Feb 25 '21 at 21:11
  • 2
    sure, not sure what my thinking was back then but 3 months ago I was still struggling to come to terms with async (even more than now anyway!) so probably was trying to pass a normal function. Anyway, sorry for the noise! – AntonOfTheWoods Feb 26 '21 at 02:55
  • 1
    This might be problematic because the coroutine is created in a different event loop than the loop in which it is run. Something like [this](https://stackoverflow.com/a/70225945), while more verbose, is probably better. – brianmaissy Dec 19 '21 at 09:26
0

Didn't quite work for me, if you are trying to let it run next to your code (example: discord wait for emote reaction aswell as add emotes), you could try to use:

asyncio.get_event_loop().create_task(FUNKTION(ARGUMENT))
GhostCat
  • 133,361
  • 24
  • 165
  • 234