Python 停止线程中的异步IO

Python 停止线程中的异步IO,python,python-3.x,python-asyncio,Python,Python 3.x,Python Asyncio,我有一个线程可以启动(并最终停止)异步IO循环,如下所示: class Ook(Thread): […] def run(self): try: self._logger.debug("Asyncio loop runs forever.") self.loop.run_forever() except Exception as ex: # We do want to se

我有一个线程可以启动(并最终停止)异步IO循环,如下所示:

class Ook(Thread):

    […]

    def run(self):
        try:
            self._logger.debug("Asyncio loop runs forever.")
            self.loop.run_forever()
        except Exception as ex:
            # We do want to see ALL unhandled exceptions here.
            self._logger.error("Exception raised: %s", ex)
            self._logger.exception(ex)
        finally:
            # Stop the loop!
            self._logger.warn('Closing asyncio event loop.')
            self.loop.run_until_complete(self.loop.shutdown_asyncgens())
            self.loop.close()

    def stop(self):
        self._logger.info("Thread has been asked to stop!")
        if self.loop.is_running():
            self._logger.debug("Asked running asyncio loop to stop.")
            for task in asyncio.Task.all_tasks():
                self.loop.call_soon_threadsafe(task.cancel)
            self.loop.call_soon_threadsafe(self.loop.stop)
一个愚蠢的(?)单元测试来检查工作是否正常

@pytest.mark.asyncio
async def test_start_and_stop_thread():
    sut = Ook()
    sut.start()
    if sut.isAlive():
        sut.stop()
        sut.join()
    assert not sut.isAlive()
    assert not sut.loop.is_running()
这不起作用,因为引发了
asyncio.cancelederror
…在
stop
方法中的任何位置捕捉这些错误似乎都没有帮助

如果我运行的测试代码没有标记为
@pytest.mark.asyncio
,我会收到一条消息说
任务已销毁,但它已挂起


我做错了什么?

我们这里有几个问题

  • Task.cancel()在例程中引发asyncio.CancelleError()。您应该在协同程序中添加一个“try/exec cancelederror”来处理该异常

  • 另一种方法是抑制def stop中的Cancelled Error异常:

    from asyncio import CancelledError
    from contextlib import suppress
    
    def stop(self):
        self._logger.info("Thread has been asked to stop!")
        if self.loop.is_running():
            self._logger.debug("Asked running asyncio loop to stop.")
            self.loop.call_soon_threadsafe(self.loop.stop)
            for task in asyncio.Task.all_tasks():
                task.cancel()
                with suppress(CancelledError):
                    loop.run_until_complete(task)
    
  • 请记住关闭所有异步发电机

    loop.run_until_complete(loop.shutdown_asyncgens())
    

  • 尝试等待几秒钟,然后检查
    isAlive
    ?@Sraw为什么会有帮助?在任何情况下,我都尝试过,但没有。因为我认为这可能是由于在
    run
    完成之前调用
    stop
    引起的。不幸的是,它似乎不是。@Sraw这是一个公平的观点。对于asyncio.task.all_tasks(self.loop)中的task,它应该是
    。如果没有参数,则返回的数组为空。