python-3.x - Python3 asyncio "Task was destroyed but it is pending"具有某些特定条件

标签 python-3.x coroutine python-asyncio

这是简化的代码,它使用 python3 协程并为 SIGING 和 SIGTERM 信号设置处理程序以正确停止作业:

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import argparse
import asyncio
import signal
import sys


def my_handler(signum, frame):
    print('Stopping')
    asyncio.get_event_loop().stop()
    # Do some staff
    sys.exit()


@asyncio.coroutine
def prob_ip(ip_addr):

    print('Ping ip:%s' % ip_addr)
    proc = yield from asyncio.create_subprocess_exec('ping', '-c', '3', ip_addr)
    ret_code = yield from proc.wait()
    if ret_code != 0:
        print("ip:%s doesn't responding" % ip_addr)
        # Do some staff
        yield from asyncio.sleep(2)
        # Do more staff
        yield from asyncio.sleep(16)


@asyncio.coroutine
def run_probing():

    print('Start probing')
    # Do some staff
    yield from asyncio.sleep(1)

    while True:
        yield from asyncio.wait([prob_ip('192.168.1.3'), prob_ip('192.168.1.2')])
        yield from asyncio.sleep(60)


def main():
    parser = argparse.ArgumentParser()
    parser.description = "Probing ip."
    parser.parse_args()

    signal.signal(signal.SIGINT, my_handler)
    signal.signal(signal.SIGTERM, my_handler)

    asyncio.get_event_loop().run_until_complete(run_probing())


if __name__ == '__main__':
    main()

当我通过以下方式运行它时:
python3 test1.py

它在没有任何警告的情况下按 Ctrl-C 停止。
但是当我通过以下方式运行它时:
python3 -m test1

它通过 Ctrl-C 打印警告:
$ python3 -m test1 
Start probing
Ping ip:192.168.1.2
Ping ip:192.168.1.3
PING 192.168.1.2 (192.168.1.2): 56 data bytes
PING 192.168.1.3 (192.168.1.3): 56 data bytes
^C--- 192.168.1.2 ping statistics ---
--- 192.168.1.3 ping statistics ---
1 packets transmitted, 0 packets received, 100% packet loss
1 packets transmitted, 0 packets received, 100% packet loss
Stopping
Task was destroyed but it is pending!
task: <Task pending coro=<prob_ip() running at /tmp/test1.py:22> wait_for=<Future pending cb=[Task._wakeup()]> cb=[_wait.<locals>._on_completion() at /usr/lib/python3.4/asyncio/tasks.py:394]>
Task was destroyed but it is pending!
task: <Task pending coro=<prob_ip() running at /tmp/test1.py:22> wait_for=<Future pending cb=[Task._wakeup()]> cb=[_wait.<locals>._on_completion() at /usr/lib/python3.4/asyncio/tasks.py:394]>

如果我通过以下方式安装此脚本,我会收到同样的警告:
from setuptools import setup

setup(name='some_scripts',
      version='1.0.0.0',
      author='Some Team',
      author_email='team@team.ru',
      url='https://www.todo.ru',
      description='Some scripts',
      packages=['my_package'],
      entry_points={'console_scripts': [
          'test1=my_package.test1:main',
      ]},
      )

我的python版本是“3.4.2”

最佳答案

好的。我想我已经弄清楚我应该如何停止所有任务。

  • 首先,据我所知。 BaseEventLoop.stop()只是停止 BaseEventLoop.run_forever() .所以应该通过 Future.cancel 取消所有任务.要获得所有任务,您可以使用 Task.all_tasks静态方法。
  • 取消所有任务后 asyncio.CancelledError 异常将从 run_until_complete 引发。因此,如果不想将其打印到 stderr,则应该捕获它。
  • 而且,在某些情况下,我会收到此错误:TypeError: signal handler must be signal.SIG_IGN, signal.SIG_DFL, or a callable object .
    我发现了一些有关此错误的主题:
  • https://bugs.python.org/issue23548
  • https://github.com/buildinspace/peru/issues/98

  • 他们都说可以通过在退出应用程序之前关闭循环来修复它。
    所以我们得到这个代码:
    #!/usr/bin/env python3
    # -*- coding: utf-8 -*-
    import asyncio
    import signal
    
    
    def my_handler():
        print('Stopping')
        for task in asyncio.Task.all_tasks():
            task.cancel()
    
    
    @asyncio.coroutine
    def do_some(some_args):
        while True:
            print("Do staff with %s" % some_args)
            yield from asyncio.sleep(2)
    
    
    def main():
        loop = asyncio.get_event_loop()
    
        loop.add_signal_handler(signal.SIGINT, my_handler)
    
        try:
            loop.run_until_complete(asyncio.wait([do_some(1), do_some(2)]))
        except asyncio.CancelledError:
            print('Tasks has been canceled')
        finally:
            loop.close()
    
    
    if __name__ == '__main__':
        main()
    

    它也适用于 signal.signal .但正如文森特 noticed loop.add_signal_handler在这种情况下看起来更好。

    但我仍然不确定这是停止所有任务的最佳方法。

    关于python-3.x - Python3 asyncio "Task was destroyed but it is pending"具有某些特定条件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33505066/

    相关文章:

    python-3.x - python3 : bytes vs bytearray, 和字符串相互转换

    Kotlin 相当于 C# Task.WhenAll

    python - 将 Cython 与 Asyncio 结合使用(Python 3.4)

    python - eventlet tpool 有什么用?

    python - 非 Web、非文件应用程序中的异步性能

    python - __await__ 是否需要成为生成器?

    python - Mrjob 无法在 dataproc 上创建集群 : __init__() got an unexpected keyword argument 'channel'

    python - 如何在python中将 float 转换为定点小数

    python - chr() 和 bytes.decode 之间的区别

    python - 异步将对象转换为协程。加载对象字段