python-3.x - 线程和异步: Task was destroyed but it is pending

标签 python-3.x python-multithreading python-asyncio

我有一个运行异步循环的线程。我开始一项 future 的任务,做一些与这里无关的事情。当我停止线程时,我也会停止异步循环。但是,我似乎无法取消池任务并获取 Task was destroyed but it is pending!

这是一个玩具示例:

from contextlib import suppress
from threading import Thread
from time import sleep
import asyncio


class Hardware(Thread):

    def __init__(self, *args, **kwargs):
        super(Hardware, self).__init__(*args, **kwargs)
        self.loop = None
        self._poll_task = None

    def run(self):
        self.loop = asyncio.new_event_loop()
        asyncio.set_event_loop(self.loop)
        self.loop.create_task(self._poll())
        self.loop.run_forever()

    async def _poll(self):
        print('ook')
        await asyncio.sleep(1.0)
        self._poll_task = asyncio.ensure_future(self._poll())
        return self._poll_task

    def stop(self):
        if self._poll_task is not None:
            self.loop.call_soon_threadsafe(self._poll_task.cancel)
        with suppress(asyncio.CancelledError):
            self.loop.call_soon_threadsafe(self.loop.stop)


hw = Hardware()
try:
    hw.start()
    while True:
        sleep(.1)
except KeyboardInterrupt:
    hw.stop()
    hw.join()

运行它输出:

; python ook.py
ook
ook
^CTask was destroyed but it is pending!
task: <Task pending coro=<Hardware._poll() running at ook.py:22> wait_for=<Future cancelled>>  

我做错了什么?

最佳答案

您不仅应该对任务调用 cancel(),还应该调用 await its cancellation而不是像你那样只是停止循环。

from contextlib import suppress
from threading import Thread
from time import sleep
import asyncio


class Hardware(Thread):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.loop = None
        self._poll_task = None

    def run(self):
        self.loop = asyncio.new_event_loop()
        loop = self.loop
        asyncio.set_event_loop(loop)
        try:
            # create task:
            self._poll_task = asyncio.ensure_future(self._poll())

            # run loop:
            loop.run_forever()
            loop.run_until_complete(loop.shutdown_asyncgens())

            # cancel task:
            self._poll_task.cancel()
            with suppress(asyncio.CancelledError):
                loop.run_until_complete(self._poll_task)
        finally:
            loop.close()

    def stop(self):
        self.loop.call_soon_threadsafe(self.loop.stop)

    async def _poll(self):
        while True:  # you don't need to create new task each time
            print('ook')
            await asyncio.sleep(1.0)


hw = Hardware()
try:
    hw.start()
    while True:
        sleep(.1)
except KeyboardInterrupt:
    hw.stop()
    hw.join()

关于python-3.x - 线程和异步: Task was destroyed but it is pending,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47514100/

相关文章:

python - 如何在 asyncio create_task 中更新全局变量

python - 在经过证书身份验证的资源上使用 python 请求下载列表文件

python - 如何在 TCP Python 聊天服务器上拥有多个客户端?

python - 如何使异步池可取消?

python - 在长时间运行的代码中使用 asyncio.sleep() 将异步函数划分为多个较小的代码部分是否合适?

python - 委托(delegate)给异步子生成器

python-3.x - 在 tkinter canvas python 上绘制 png 图像

python - 使用编码打开内存映射文件

Python:如何将从列表中以某个字母开头的元素复制到新列表中或从列表中删除不以字母开头的元素

multithreading - WSGI的线程和进程怎么统计?