# Non-blocking asyncio calls with PyCall

**URL:** <https://discourse.julialang.org/t/non-blocking-asyncio-calls-with-pycall/36685>\
**Category:** General Usage\
**Tags:** question, pycall\
**Created:** [March 29, 2020, 6:23pm UTC](https://discourse.julialang.org/t/non-blocking-asyncio-calls-with-pycall/36685 "2020-03-29T18:23:09Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![mkosch](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mkosch/32/14095_2.png) [@mkosch](https://discourse.julialang.org/u/mkosch)\
**Post date:** [March 29, 2020, 6:23pm UTC](https://discourse.julialang.org/t/non-blocking-asyncio-calls-with-pycall/36685/1 "2020-03-29T18:23:09Z")

</div>

Hello everyone,

I am currently trying to integrate asyncronous Python functions that use asyncio into Julia’s coroutine framework. My problem is similar to the following example:

```julia
using PyCall
asyncio = pyimport("asyncio")

py"""
async def sleep_well(time):
        print("Falling asleep...")
        await $asyncio.sleep(time)
        print("Wake up!")
"""

loop = asyncio.get_event_loop()
@async loop.run_until_complete(py"sleep_well"(3))

```

Since PyCall uses a simple ccall under the hood, the last line is of course not running asynchronously.  
Is there a way to change that, for example by calling Julia’s yield() from Python and notifying Julia when the work is done?

I found this [old question](https://discourse.julialang.org/t/async-calls-to-c-api-yields/15399) which goes in the same direction but I could not manage to get any of the proposed approaches working.

---

<div class="post-metadata">

**Author:** ![stevengj](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevengj/32/71_2.png) [@stevengj](https://discourse.julialang.org/u/stevengj)\
**Post date:** [March 29, 2020, 6:40pm UTC](https://discourse.julialang.org/t/non-blocking-asyncio-calls-with-pycall/36685/2 "2020-03-29T18:40:07Z")

</div>

A basic issue is that `asyncio` expects its own event loop, which is different from the libuv event loop used by Julia.

Apparently it is possible to hack `asyncio` to use a libuv event loop — see [https://github.com/MagicStack/uvloop](https://github.com/MagicStack/uvloop) — and maybe this could be used to integrate it with Julia, but you’d have to dig into the guts of the `uvloop` implementation.

---

<div class="post-metadata">

**Author:** ![mkosch](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mkosch/32/14095_2.png) [@mkosch](https://discourse.julialang.org/u/mkosch)\
**Post date:** [March 29, 2020, 7:46pm UTC](https://discourse.julialang.org/t/non-blocking-asyncio-calls-with-pycall/36685/3 "2020-03-29T19:46:11Z")

</div>

Thank you for the fast response!  
I just gave the uvloop package a first (naive) try:

```julia
using PyCall
asyncio = pyimport("asyncio")
uvloop = pyimport("uvloop")

py"""
async def sleep_well(time):
        print("Falling asleep...")
        await $asyncio.sleep(time)
        print("Wake up!")
"""

loop = uvloop.new_event_loop()
asyncio.set_event_loop(loop) # Edit: This line should instead be asyncio.set_event_loop_policy(uvloop.EventLoopPolicy())
@async loop.run_until_complete(py"sleep_well"(3))

```

`loop` turned into a `uvloop` now but (as expected) the last line is still not running asynchronously. I am not really familiar with libuv, but I assume that instead of using `uvloop.new_event_loop()` the handle to Julia’s uvloop (`Base.eventloop()`?) needs to be converted to a uvloop object and passed to asyncio.

Could this be the right way or am I getting something wrong already?

---

<div class="post-metadata">

**Author:** ![stevengj](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevengj/32/71_2.png) [@stevengj](https://discourse.julialang.org/u/stevengj)\
**Post date:** [March 29, 2020, 7:51pm UTC](https://discourse.julialang.org/t/non-blocking-asyncio-calls-with-pycall/36685/4 "2020-03-29T19:51:14Z")

</div>

> [@mkosch](#):
>
> the handle to Julia’s uvloop ( `Base.eventloop()` ?) needs to be converted to a uvloop object and passed to asyncio.

Julia doesn’t have an “event-loop object” — that is not part of libuv. The point of the `uvloop`, as I understand it, is to take libuv and wrap it in Python objects that mimic asyncio’s APIs.

You will have to look at how `uvloop` is implemented, and how Julia’s event loop is implemented, and translate the concepts as needed. This will take some digging.

---

<div class="post-metadata">

**Author:** ![mkosch](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mkosch/32/14095_2.png) [@mkosch](https://discourse.julialang.org/u/mkosch)\
**Post date:** [March 29, 2020, 8:27pm UTC](https://discourse.julialang.org/t/non-blocking-asyncio-calls-with-pycall/36685/5 "2020-03-29T20:27:02Z")

</div>

Alright, then I start digging. Thank you again!

---

<div class="post-metadata">

**Author:** ![tkf](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tkf/32/17635_2.png) [@tkf](https://discourse.julialang.org/u/tkf)\
**Post date:** [March 31, 2020, 12:38am UTC](https://discourse.julialang.org/t/non-blocking-asyncio-calls-with-pycall/36685/6 "2020-03-31T00:38:08Z")

</div>

> [@stevengj](#):
>
> Apparently it is possible to hack `asyncio` to use a libuv event loop

IIUC `asyncio`’s event loop is pluggable by design. For example, there is [`asyncio.set_event_loop`](https://docs.python.org/3/library/asyncio-eventloop.html#asyncio.set_event_loop) for setting a current event loop for the current OS thread.

@mkosch You might have discovered it already but [`asyncio.AbstractEventLoop`](https://docs.python.org/3.6/library/asyncio-eventloop.html) seems to be a good starting point. Presumably you need to implement this interface using PyCall for a full interop.

If you just want to a quick fake solution, maybe you can do something like [ipyjulia\_hacks — ipyjulia\_hacks 0 documentation](https://ipyjulia-hacks.readthedocs.io/en/latest/#fake-asyncio-integration) (it just polls in background)
