Python3 asyncio "Task was destroyed but it is pending" 具有某些特定条件
Python3 asyncio "Task was destroyed but it is pending" with some specific condition
这里是简化的代码,它使用 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”
使用asyncio.gather代替asyncio.wait
:
Cancellation: if the outer Future is cancelled, all children (that have not completed yet) are also cancelled.
示例:
def handler(future, loop):
future.cancel()
loop.stop()
@asyncio.coroutine
def do_some(arg):
while True:
print("Do stuff with %s" % arg)
yield from asyncio.sleep(2)
loop = asyncio.get_event_loop()
future = asyncio.gather(do_some(1), do_some(2))
loop.add_signal_handler(signal.SIGINT, handler, future, loop)
loop.run_forever()
好的。我想我已经弄清楚应该如何停止所有任务了。
- 首先,据我了解。 BaseEventLoop.stop() is only to stop BaseEventLoop.run_forever(). So one should cancel all tasks via Future.cancel. To get all tasks you can use Task.all_tasks 静态方法。
- 取消所有任务后 asyncio.CancelledError 将从 run_until_complete 引发异常。所以如果不想将它打印到 stderr,应该抓住它。
而且,在某些情况下,我会收到此错误:TypeError: signal handler must be signal.SIG_IGN, signal.SIG_DFL, or a callable object
。
我找到了一些关于这个错误的主题:
都说退出应用前关闭循环可以解决
所以我们得到这个代码:
#!/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. But as Vincent loop.add_signal_handler 在这种情况下看起来更好。
但我仍然不确定这是停止所有任务的最佳方法。
这里是简化的代码,它使用 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”
使用asyncio.gather代替asyncio.wait
:
Cancellation: if the outer Future is cancelled, all children (that have not completed yet) are also cancelled.
示例:
def handler(future, loop):
future.cancel()
loop.stop()
@asyncio.coroutine
def do_some(arg):
while True:
print("Do stuff with %s" % arg)
yield from asyncio.sleep(2)
loop = asyncio.get_event_loop()
future = asyncio.gather(do_some(1), do_some(2))
loop.add_signal_handler(signal.SIGINT, handler, future, loop)
loop.run_forever()
好的。我想我已经弄清楚应该如何停止所有任务了。
- 首先,据我了解。 BaseEventLoop.stop() is only to stop BaseEventLoop.run_forever(). So one should cancel all tasks via Future.cancel. To get all tasks you can use Task.all_tasks 静态方法。
- 取消所有任务后 asyncio.CancelledError 将从 run_until_complete 引发异常。所以如果不想将它打印到 stderr,应该抓住它。
而且,在某些情况下,我会收到此错误:
TypeError: signal handler must be signal.SIG_IGN, signal.SIG_DFL, or a callable object
。 我找到了一些关于这个错误的主题:都说退出应用前关闭循环可以解决
所以我们得到这个代码:
#!/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. But as Vincent
但我仍然不确定这是停止所有任务的最佳方法。