【问题标题】:Asyncio: How to cleanup instance of class in __del__ method when we need to use async methodsAsyncio:当我们需要使用异步方法时,如何在 __del__ 方法中清理类的实例
【发布时间】:2020-03-26 15:08:41
【问题描述】:

假设一个类需要一个异步协程来清理:

import asyncio                                                                                                          

class AsyncClient:                                                                                                      

    async def do_something(self):                                                                                       
        print ('Doing something')                                                                                       
        await asyncio.sleep(1)                                                                                          
        print ('Something done')                                                                                        

    async def cleanup(self):                                                                                            
        print ('Starting cleanup')                                                                                      
        await asyncio.sleep(1)                                                                                          
        print ('Cleanup in progress 1/3')                                                                               
        await asyncio.sleep(1)                                                                                          
        print ('Cleanup in progress 2/3')                                                                               
        await asyncio.sleep(1)                                                                                          
        print ('Cleanup in progress 3/3')                                                                               

    def __del__(self):
        **CODE_HERE_SHOULD_CALL_CLEANUP**

dunder方法中不允许使用await。

我应该在__del__ 方法中添加什么来允许在这两种情况下进行清理:

client = AsyncClient() 

async def main():                                                                                                                                                                                                        
    await client.do_something()                                                                                         

asyncio.run(main())

async def main():                                                                                                       
    client = AsyncClient()                                                                                              
    await client.do_something()                                                                                         

asyncio.run(main())

我尝试执行以下操作,这适用于第一种情况,但不适用于第二种情况(如果循环不再存在,我会重新创建一个循环):

    def __del__(self):                                                                                                  
        print ('__del__()')                                                                                             
        try:                                                                                                            
            loop = asyncio.get_event_loop()                                                                             
        except RuntimeError:                                                                                            
            loop = asyncio.new_event_loop()                                                                             
            asyncio.set_event_loop(loop)                                                                                
            asyncio.run(self.cleanup())                                                                                 
            return                                                                                                      

        cleanup_task = loop.create_task(self.cleanup())

【问题讨论】:

  • 您可能希望使用上下文管理器,而不是依赖 __del__ 来调用。

标签: python python-asyncio python-3.8


【解决方案1】:

清理不应该取决于何时(或是否)__del__ 被调用。定义一个清理方法,或者显式调用它,或者让上下文管理器为你隐式调用它。

import asyncio

class AsyncClient:

    async def do_something(self):
        print ('Doing something')
        await asyncio.sleep(1)
        print ('Something done')

    async def cleanup(self):
        print ('Starting cleanup')
        await asyncio.sleep(1)
        print ('Cleanup in progress 1/3')
        await asyncio.sleep(1)
        print ('Cleanup in progress 2/3')
        await asyncio.sleep(1)
        print ('Cleanup in progress 3/3')

    async def __aenter__(self):
       return self

    async def __aexit__(self, *args):
        await self.cleanup()

然后

client = AsyncClient()

async def main():
    await client.do_something()
    await client.cleanup()

asyncio.run(main())

或类似的东西

client = AsyncClient()

async def main():
    async with client:
        await client.do_something()

asyncio.run(main())

【讨论】:

    猜你喜欢
    • 2013-12-18
    • 1970-01-01
    • 1970-01-01
    • 2018-01-23
    • 2019-03-19
    • 2020-02-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多