Please explain “Task was destroyed but it is pending!”

前端 未结 4 759
难免孤独
难免孤独 2021-02-06 22:54

Python 3.4.2

I am learning asyncio and I use it to continously listen IPC bus, while gbulb listens to the dbus.

Some side notes:

So I created a fun

4条回答
  •  陌清茗
    陌清茗 (楼主)
    2021-02-06 22:55

    The meaning of the issue is that a loop doesn't have time to finish all the tasks.

    This arranges for a CancelledError to be thrown into the wrapped coroutine on the next cycle through the event loop.

    There is no chance to do a "next cycle" of the loop in your approach. To make it properly you should move a stop operation to a separate non-cyclic coroutine to give your loop a chance to finish.

    Second significant thing is CancelledError raising.

    Unlike Future.cancel(), this does not guarantee that the task will be cancelled: the exception might be caught and acted upon, delaying cancellation of the task or preventing cancellation completely. The task may also return a value or raise a different exception.

    Immediately after this method is called, cancelled() will not return True (unless the task was already cancelled). A task will be marked as cancelled when the wrapped coroutine terminates with a CancelledError exception (even if cancel() was not called).

    So after cleanup your coroutine must raise CancelledError to be marked as cancelled.

    Using an extra coroutine to stop the loop is not an issue because it is not cyclic and be done immediately after execution.

    def main():                                              
        loop = asyncio.get_event_loop()                      
        asyncio.ensure_future(listen_to_ipc_channel_layer()) 
                                                         
        for sig in (signal.SIGINT, signal.SIGTERM):          
            loop.add_signal_handler(sig, ask_exit)           
        loop.run_forever()                                   
        print("Close")                                       
        loop.close()                                         
                                                         
                                                         
    @asyncio.coroutine                                       
    def listen_to_ipc_channel_layer():                       
        while True:                                          
            try:                                             
                print("Running")                                 
                yield from asyncio.sleep(0.1)                
            except asyncio.CancelledError as e:              
                print("Break it out")                        
                raise e # Raise a proper error
                                                         
                                              
    # Stop the loop concurrently           
    @asyncio.coroutine                                       
    def exit():                                              
        loop = asyncio.get_event_loop()                      
        print("Stop")                                        
        loop.stop()                                          
    
    
    def ask_exit():                          
        for task in asyncio.Task.all_tasks():
            task.cancel()                    
        asyncio.ensure_future(exit())        
                                         
                                         
    if __name__ == "__main__":               
        main()                               
    

提交回复
热议问题