当loop.run_until_complete工作时asyncio.run失败 [英] asyncio.run fails when loop.run_until_complete works

查看:514
本文介绍了当loop.run_until_complete工作时asyncio.run失败的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

此代码失败:

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())

出现此错误:

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

当我用loop取消注释两行并注释asyncio.run时,它运行良好.什么事?我以为asyncio.run是这两行的捷径.

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.

问题出在motor_asyncio实现中,因为当我将main更改为简单的return 42时,asyncio.run也能很好地工作.

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

推荐答案

怎么回事?我以为asyncio.run是这两个的捷径 线.

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

不,它还有很多其他功能.特别是它创建并设置新事件环形.这就是为什么会出现错误的原因:AsyncIOMotorClient()为默认事件循环创建了一些异步内容,但是asyncio.run创建的另一个循环尝试使用它.

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.

如果要保留asyncio.run,则应将init内容移入main():

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.

这篇关于当loop.run_until_complete工作时asyncio.run失败的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆