asyncio.run fails when loop.run_until_complete works

随声附和 提交于 2019-12-11 06:05:46

问题


This code fails:

import asyncio
from motor import motor_asyncio


_client = motor_asyncio.AsyncIOMotorClient()
_db = _client.db

users = _db.users


async def main():
    await users.create_index(
        'login',
        unique=True
    )


if __name__ == '__main__':
    #loop = asyncio.get_event_loop()
    #loop.run_until_complete(main())
    asyncio.run(main())

With this error:

Traceback (most recent call last):
  File "/home/sanyash/myrepos/TKP/db.py", line 21, in <module>
    asyncio.run(main())
  File "/usr/local/lib/python3.7/asyncio/runners.py", line 43, in run
    return loop.run_until_complete(main)
  File "/usr/local/lib/python3.7/asyncio/base_events.py", line 584, in run_until_complete
    return future.result()
  File "/home/sanyash/myrepos/TKP/db.py", line 14, in main
    unique=True
RuntimeError: Task <Task pending coro=<main() running at /home/sanyash/myrepos/TKP/db.py:14> cb=[_run_until_complete_cb() at /usr/local/lib/python3.7/asyncio/base_events.py:158]> got Future <Future pending cb=[run_on_executor.<locals>._call_check_cancel() at /usr/local/lib/python3.7/motor/frameworks/asyncio/__init__.py:80]> attached to a different loop

When I uncomment two lines with loop and comment asyncio.run it works well. What the matter? I thought asyncio.run is a shortcut for this two lines.

The problem is something in the motor_asyncio implementation, because when I changed main to simple return 42, asyncio.run works well too.


回答1:


What the matter? I thought asyncio.run is a shortcut for this two lines.

No, it does much more. In particular it creates and sets an new event loop. And this is why you get error: AsyncIOMotorClient() creates some async stuff for default event loop, but another loop created by asyncio.run tries to use it.

If you want to preserve asyncio.run you should move init stuff inside main():

# ...

_client = None
_db = None
users = None


async def main():
    global _client, _db, users
    _client = motor_asyncio.AsyncIOMotorClient()
    _db = _client.db
    users = _db.users

    # ...

It's a good idea in general to start things when event loop is already set and running instead of doing something at module-level.



来源:https://stackoverflow.com/questions/55425797/asyncio-run-fails-when-loop-run-until-complete-works

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!