Exception “ There is no current event loop in thre

2019-02-17 15:50发布

问题:

The is the simple test code and the result.

import asyncio

async def test():
    await asyncio.sleep(1)

if __name__ == '__main__':

    asyncio.set_event_loop(None)      # Clear the main loop.
    loop = asyncio.new_event_loop()   # Create a new loop.
    loop.run_until_complete(test())   # Run coroutine over the new loop

Traceback (most recent call last):
  File "test_test.py", line 11, in <module>
    loop.run_until_complete(test())
  File "/usr/lib/python3.5/asyncio/base_events.py", line 387, in run_until_complete
    return future.result()
  File "/usr/lib/python3.5/asyncio/futures.py", line 274, in result
    raise self._exception
  File "/usr/lib/python3.5/asyncio/tasks.py", line 239, in _step
    result = coro.send(None)
  File "test_test.py", line 5, in test
    await asyncio.sleep(1)
  File "/usr/lib/python3.5/asyncio/tasks.py", line 510, in sleep
    loop = events.get_event_loop()
  File "/usr/lib/python3.5/asyncio/events.py", line 632, in get_event_loop
    return get_event_loop_policy().get_event_loop()
  File "/usr/lib/python3.5/asyncio/events.py", line 578, in get_event_loop
    % threading.current_thread().name)
RuntimeError: There is no current event loop in thread 'MainThread'.

I run the async def test() over the new loop and expected that asyncio.sleep(1) which is nested by test() also use the new loop.

In contrast to that, sleep() still seems to access main loop I set as None.

I know I can re-set a main loop as the new loop with asyncio.set_event_loop(loop) before calling run_until_complete() and it will work with no exception.

However, I want to know it is normal for asyncio that main loop Must be set and is used for coroutines regardless of a loop over which coroutine is run.

回答1:

I want to know it is normal for asyncio that main loop Must be set and is used for coroutines regardless of a loop over which coroutine is run.

This used to be required prior to Python 3.6. The reason is that functions like asyncio.sleep() need an event loop to be able to use loop.call_later() to schedule a wake-up call to complete the future.

As of Python 3.6 (or 3.5.3, which included a fix for the issue), when get_event_loop() is invoked from a coroutine driven by an event loop, it always returns the event loop that drives it. As a result, your code works correctly.

This is covered by the following sentence in the documentation:

An exception to this rule happens when get_event_loop() is called from a running future/coroutine, in which case it will return the current loop running that future/coroutine.