Thread and asyncio: Task was destroyed but it is pending

倖福魔咒の 提交于 2019-11-30 20:05:45

问题


I have a thread that runs an asyncio loop. I start a future task that does things which are irrelevant here. When I stop the thread, I stop the asyncio loop as well. However, I cannot seem to cancel the pool task and get Task was destroyed but it is pending!

Here is a toy example:

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()

Running it outputs:

; 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>>  

What am I doing wrong?


回答1:


You should not only call cancel() on task, but also await its cancellation instead of just stopping loop as you do.

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()


来源:https://stackoverflow.com/questions/47514100/thread-and-asyncio-task-was-destroyed-but-it-is-pending

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!