【问题标题】:RuntimeError: Task attached to a different loopRuntimeError:附加到不同循环的任务
【发布时间】:2017-01-11 06:37:15
【问题描述】:

您好,我正在使用 AsyncIOMotorClient 对 mongoDb 进行异步数据库调用。 下面是我的代码。

xyz.py
async def insertMany(self,collection_name,documents_to_insert):
    try:
        collection=self.database[collection_name]
        document_inserted = await collection.insert_many(documents_to_insert)
        return document_inserted
    except Exception:
        raise

def insertManyFn(self,collection_name,documents_to_insert):
    try:
        loop=asyncio.new_event_loop()
        asyncio.set_event_loop(loop)
        loop1=asyncio.get_event_loop()
        inserted_documents_count = loop1.run_until_complete(self.insertMany(collection_name, documents_to_insert))
        if inserted_documents_count==len(documents_to_insert):
            document_to_insert={Config.DB_JOB_COLUMN:Job.job_id,Config.DB_JOB_RESULT_COLUMN:Config.DB_JOB_RESULT_SUCCESS}
            loop1.run_until_complete(self.insertOne(Config.DB_JOB_COLLECTION, document_to_insert))
    except Exception:
        raise

xyz1.py
t=Timer(10,xyz.insertManyFn,\
                (collection_name,documents_to_insert))
t.start()   

运行时出现异常

RuntimeError: Task <Task pending coro=<xyz.insertMany() running at <my workspace location>/xyz.py:144> cb=[_run_until_complete_cb() at /usr/lib64/python3.5/asyncio/base_events.py:164]> got Future <Future pending cb=[_chain_future.<locals>._call_check_cancel() at /usr/lib64/python3.5/asyncio/futures.py:431]> attached to a different loop

在上述程序中,insertManyFn 将在 10 秒后调用并执行插入操作。但是当它第一次调用 insertMany 时,我遇到了一个异常。

【问题讨论】:

    标签: mongodb python-asyncio tornado-motor


    【解决方案1】:

    我仍然希望我的 MotorClient 位于模块的顶层,所以这就是我所做的:我修补 MotorClient.get_io_loop 以始终返回当前循环。

    import asyncio
    import motor.core
    
    from motor.motor_asyncio import (
        AsyncIOMotorClient as MotorClient,
    )
    
    # MongoDB client
    client = MotorClient('mongodb://localhost:27017/test')
    client.get_io_loop = asyncio.get_running_loop
    
    # The current database ("test")
    db = client.get_default_database()
    
    
    # async context
    async def main():
        posts = db.posts
        await posts.insert_one({'title': 'great success!')
    
    
    # Run main()
    asyncio.run(main())
    

    【讨论】:

    • 谢谢,我遇到了与 op 相同的错误,添加 client.get_io_loop = asyncio.get_running_loop 有帮助,但我不明白为什么会这样?
    • @y_159 显然,应用程序可以初始化多个循环。但是,如果您的运行循环与创建的一个电机不同,那么您就有麻烦了 :) 这个 hack 确保每个人都使用相同的循环
    • 很棒的补丁,谢谢!问题是为什么电机在 docker 内启动另一个循环?当我用 docker 得到这个异常时,但没有它。
    【解决方案2】:

    根据documentation,如果你不使用默认的,AsyncIOMotorClient 应该传递一个ioloop。创建事件循环后尝试创建客户端:

    loop=asyncio.new_event_loop()
    asyncio.set_event_loop(loop)
    client = AsyncIOMotorClient(io_loop=loop)
    

    【讨论】:

    • 尝试这样做但出现错误,TypeError: '_UnixSelectorEventLoop' object is not iterable
    • 对不起,电话应该是:AsyncIOMotorClient(io_loop=loop)
    • 我再次收到异常“任务附加到不同的循环”
    【解决方案3】:

    我已经修改了代码,它正在工作。

    def insertManyFn(self,loop,collection_name,documents_to_insert):
        try:
            inserted_documents_count = loop.run_until_complete(self.insertMany(event_loop,collection_name, documents_to_insert))
            if len(inserted_documents_count)==len(documents_to_insert):
                document_to_insert={Config.DB_JOB_COLUMN:Job.job_id,Config.DB_JOB_RESULT_COLUMN:Config.DB_JOB_RESULT_SUCCESS}
                loop1.run_until_complete(self.insertOne(Config.DB_JOB_COLLECTION, document_to_insert))
        except Exception:
            raise
    
    loop=asyncio.get_event_loop()   
    t=Timer(10,self.xyz.insertManyFn,(loop,collection_name,documents_to_insert))
    t.start()
    

    说明-我正在使用 python 线程计时器,它创建自己的线程以在一定时间后执行函数。所以,在这个线程中,我得到了不应该是正确方法的事件循环,它应该首先得到事件循环并在其中创建一个计时器线程。 我想这是唯一的原因。

    【讨论】:

    • @Udi 感谢您的帮助。我想知道一件事,我的应用程序支持异步 CRUD 操作,所以对于每个操作我都会得到一个事件循环。这种方法可以吗?
    • 否 - 您的整个应用程序应该在一个事件循环中运行。
    • 当我们想要在整个操作(在我的情况下是插入)完成后返回(比如 op.id)时,您使用 asyncio.ensure_future() 而不是 python 计时器的参考工作正常。但是当我们必须先返回并且插入将在后台发生时该怎么办。
    • ensure_future 立即返回。
    猜你喜欢
    • 1970-01-01
    • 2023-03-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-24
    • 1970-01-01
    • 2021-06-01
    相关资源
    最近更新 更多