2015-11-03 9 views
8

यहाँ सरल है कोड है, जो python3 coroutine का उपयोग करता है और काम ठीक से रोकने के SIGING और SIGTERM संकेतों के लिए हैंडलर सेट के साथ:python3 asyncio "टास्क नष्ट हो गया था, लेकिन यह लंबित है" कुछ विशिष्ट हालत

#!/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 द्वारा चेतावनी प्रिंट:

from setuptools import setup 

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

मेरे अजगर:

$ 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]> 

ही चेतावनी मैं अगर मैं इस स्क्रिप्ट के माध्यम से स्थापित संस्करण "3.4.2"

+1

आप [loop.add_signal_handler] (https://docs.python.org/3/library/asyncio-eventloop.html#asyncio.BaseEventLoop.add_signal_handler) का उपयोग करना चाह सकते हैं, हालांकि यह आपकी समस्या से संबंधित नहीं है। – Vincent

+0

हां, धन्यवाद, इस तरह मेरे मामले में बेहतर दिखता है। लेकिन यह मदद नहीं करता है। मुझे अभी भी वही चेतावनियां मिलती हैं। – willir

उत्तर

8

ठीक है। मुझे लगता है कि मैंने यह पता लगाया है कि मुझे सभी कार्यों को कैसे रोकना चाहिए।

  1. सबसे पहले, जहां तक ​​मैं समझता हूं। BaseEventLoop.stop() केवल BaseEventLoop.run_forever() को रोकने के लिए है। इसलिए Future.cancel के माध्यम से सभी कार्यों को रद्द करना चाहिए। सभी कार्यों को प्राप्त करने के लिए आप Task.all_tasks स्थैतिक विधि का उपयोग कर सकते हैं।
  2. रद्दीकरण के बाद सभी कार्यों asyncio.CancelledError अपवाद run_until_complete से उठाया जाएगा। इसलिए किसी को इसे पकड़ना चाहिए, अगर कोई इसे stderr पर प्रिंट नहीं करना चाहता है।
  3. और कुछ मामलों में, मुझे यह त्रुटि मिलती है: 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 साथ भी काम करता है:

तो हम इस कोड को मिलता है। लेकिन विन्सेंट noticedloop.add_signal_handler इस मामले में बेहतर दिखता है।

लेकिन मुझे अभी भी यकीन नहीं है कि यह सभी कार्यों को रोकने का सबसे अच्छा तरीका है।

+1

(1) वायदा के विपरीत, कार्य '.cancel() '(कैचेलर एरर' पकड़ें) को अनदेखा कर सकते हैं (2) यदि कार्यों को साफ करने की आवश्यकता है तो आप [' loop.run_until_complete (asyncio.gather (* asyncio.Task.all_tasks())) 'loop.close()'] से पहले (http://stackoverflow.com/q/27796294/4279) – jfs

+0

यदि आप सिग्नल हैंडलर को सभी चल रहे कार्यों को रद्द करना नहीं चाहते हैं, तो एक नज़र डालें मेरा जवाब (संपादित)। – Vincent

+0

@ जेएफ। सेबेस्टियन हां, धन्यवाद, मुझे बाहर निकलने से पहले अधूरे कार्यों की प्रतीक्षा करनी है। लेकिन (मुझे नहीं पता क्यों) asyncio.gather इस मामले में काम नहीं करता है (python3.5.0 में सूची में)। asyncio.wait काम करता है, इसलिए हमें ऐसा कोड मिलता है: https://gist.github.com/willir/b521450b66be6e6b238c। संपादित करें: मुझे भी नहीं पता कि मुझे एसिन्सीओ को पकड़ने की आवश्यकता क्यों नहीं है। इस से (वास्तव में दूसरा) lop.run_until_complete त्रुटि। – willir

2

asyncio.wait के बजाय asyncio.gather का उपयोग करें :

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() 
संबंधित मुद्दे