问题描述:

一个使用 Apscheduler 定时启动 Aiohttp 下载文件的小工具,在不使用 apscheduler 的时候,可以正常工作。

使用 apscheduler 后则会类似出现以下错误:

loop = asyncio.get_event_loop()
File "/usr/local/python3.7.4/lib/python3.7/asyncio/events.py", line 644, in get_event_loop
% threading.current_thread().name)
RuntimeError: There is no current event loop in thread 'ThreadPoolExecutor-0_1'.

在查看 get_event_loop 源码的时候,发现以下问题:

def get_event_loop():
    """Return an asyncio event loop.

    When called from a coroutine or a callback (e.g. scheduled with call_soon
    or similar API), this function will always return the running event loop.

    If there is no running event loop set, the function will return
    the result of `get_event_loop_policy().get_event_loop()` call.
    """
    # NOTE: this function is implemented in C (see _asynciomodule.c)
    current_loop = _get_running_loop()
    if current_loop is not None:
        return current_loop
    return get_event_loop_policy().get_event_loop()

注释中很明确的说明:当从协程中调用时,此函数将始终返回正在运行的 loop, 而不是新建 Loop

至此异常根源明白:由于我是在 Apscheduler 线程中运行的 Loop 所以,在get_event_loop 时获取到的是 Apscheduler 的创建的线程,而 Apscheduler 的线程并不是一个loop 所以就会抛出以上错误。


解决办法:

很简单,修改成以下这样即可:

loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)

显式设置一下事件循环即可。