python-asynciouvloop

Using alternative event loop without setting global policy


I'm using uvloop with websockets as

import uvloop
coro = websockets.serve(handler, host, port)  # creates new server
loop = uvloop.new_event_loop()
loop.create_task(coro)
loop.run_forever()

It works fine, I'm just wondering whether I could run to some unexpected problems without setting the global asyncio policy to uvloop. As far as I understand, not setting the global policy should work as long as nothing down there doesn't use the global asyncio methods, but works with the passed-down event loop directly. Is that correct?


Solution

  • There are three main global objects in asyncio:

    All the attempts to get the current context in asyncio go through a single function, asyncio.get_event_loop.

    One thing to remember is that since Python 3.6 (and Python 3.5.3+), get_event_loop has a specific behavior:

    Example 1:

    import uvloop
    asyncio.set_event_loop_policy(uvloop.EventLoopPolicy())
    loop = asyncio.get_event_loop()
    loop.run_forever()
    

    Here the policy is the uvloop policy. The loop returned by get_event_loop is a uvloop, and it is set as the default loop for this thread. When this loop is running, it is registered as the running loop.

    In this example, calling get_event_loop() anywhere in this thread returns the right loop.

    Example 2:

    import uvloop
    loop = uvloop.new_event_loop()
    asyncio.set_event_loop(loop)
    loop.run_forever()
    

    Here the policy is still the default policy. The loop returned by new_event_loop is a uvloop, and it is set as the default loop for this thread explicitly using asyncio.set_event_loop. When this loop is running, it is registered as the running loop.

    In this example, calling get_event_loop() anywhere in this thread returns the right loop.

    Example 3:

    import uvloop
    loop = uvloop.new_event_loop()
    loop.run_forever()
    

    Here the policy is still the default policy. The loop returned by new_event_loop is a uvloop, but it is not set as the default loop for this thread. When this loop is running, it is registered as the running loop.

    In this example, calling get_event_loop() within a coroutine returns the right loop (the running uvloop). But calling get_event_loop() outside a coroutine will result in a new standard asyncio loop, set as the default loop for this thread.

    So the first two approaches are fine, but the third one is discouraged.