Skip to main content
 首页 » 编程设计

python之asyncio.run 在 loop.run_until_complete 工作时失败

2025年05月04日20www_RR

此代码失败:

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 是这两行的快捷方式。

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

请您参考如下方法:

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

不,它做的更多。特别是它creates and sets一个新的事件循环。这就是您收到错误的原因:AsyncIOMotorClient() 为默认事件循环创建了一些异步内容,但 asyncio.run 创建的另一个循环尝试使用它。

如果你想保留 asyncio.run,你应该将初始化内容移到 main() 中:

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

一般来说,在事件循环已经设置并运行时开始事情是个好主意,而不是在模块级别做某事。