2016-11-01 2 views
2

나는 파이썬 asyncio으로 놀고있다. 내 프로그램에는 3 개의 코 루틴 만 있습니다. 그들 중 2 명은 직접 일정을 계획하고 3 명은 포스터 중 한 명으로부터 계획을 세웁니다. 실제로 이 취소되었습니다 coro2이 취소되지 않은 이유왜 부모의 coroutine이 취소되지 않았습니까?

coro1 
coro2 
coro3 
^CExiting... Cancelling all tasks 
Cancellation is done! 
coro3 exc CancelledError() 
coro1 exc CancelledError() 
Task was destroyed but it is pending! 
task: <Task pending coro=<coro2() running at test.py:15> wait_for=<Task cancelled coro=<coro3() done, defined at test.py:23>>> 

그래서 궁금하고, coro3 :

import asyncio 

async def coro1(): 
    try: 
     print('coro1') 
     await asyncio.sleep(1000) 
    except Exception as e: 
     print('coro1 exc %s' % repr(e)) 
     raise 

async def coro2(): 
    try: 
     print('coro2') 
     await asyncio.ensure_future(coro3()) 
     await asyncio.sleep(1000) 
    except Exception as e: 
     print('coro2 exc %s' % repr(e)) 
     raise 

async def coro3(): 
    try: 
     print('coro3') 
     await asyncio.sleep(1000) 
    except Exception as e: 
     print('coro3 exc %s' % repr(e)) 
     raise 

loop = asyncio.get_event_loop()  
try: 
    f1 = asyncio.ensure_future(coro1()) 
    f2 = asyncio.ensure_future(coro2())  
    loop.run_forever() 
except KeyboardInterrupt: 
    print('Exiting... Cancelling all tasks') 

    f2.cancel() 
    f1.cancel() 

    # This code gives the same result: 
    # for task in asyncio.tasks.Task.all_tasks(loop): 
    # task.cancel() 

    print('Cancellation is done!') 

    loop.stop() 
    loop.run_forever() 
finally: 
    loop.close() 

이 코드는 다음 출력을 생성 : 그리고 사용자가 Ctrl+C가 누를 때 제대로 내 프로그램을 마무리 할 ?

+0

코 루틴 2는 코 루틴 3이 반환 된 후 추가로 1000 초 동안 휴면합니다. 수면 시간을 줄이거 나 (또는 ​​1000 초를 기다려보십시오!) – shongololo

+0

@ shongololo, 나는 'a sleep sleep (1000)'을 전혀 삭제하지 않더라도 관찰 된 행동은 변하지 않을까 걱정됩니다. –

+0

아, 스크롤 막대에 숨겨진 코드 샘플의 가장 낮은 줄을 보지 못했습니다. 코 루틴 2가 예외를 반환 할 기회를 얻지 못하고 루프가 닫힐 때까지 종료 될 수 있습니다. 루프를 닫기 전에 모든 작업이 취소되었는지 확인할 때까지 기다릴 수는 있지만 예외가 표시되지는 않습니다. – shongololo

답변

2

알 수 있습니다. 문제는 except 블록이 두 줄을이었다

# ... 
loop.stop() 
loop.run_forever() 

예상 취소 전파 인해 loop.stop()에 작동하지 않았다. 하나는 이런 식으로 코드를 변경하는 경우 :

# ... 

try: 
    f1 = asyncio.ensure_future(coro1()) 
    f2 = asyncio.ensure_future(coro2())  
    loop.run_forever() 
except KeyboardInterrupt: 
    print('Exiting... Cancelling all tasks') 
    f2.cancel() 
    f1.cancel() 
    print('Cancellation is done!')  
    try: 
     loop.run_forever() 
     # Wait a very short time for f2 cancelation and press Ctrl+C again. 
    except KeyboardInterrupt: 
     loop.stop() 
     loop.run_forever() 
finally: 
    loop.close() 

메시지 Task was destroyed but it is pending! 멀리 갈 것입니다.

f1 = asyncio.ensure_future(coro1()) 
f2 = asyncio.ensure_future(coro2()) 
tasks = asyncio.gather(f1, f2) 
try: 
    loop.run_until_complete(tasks) 
except KeyboardInterrupt: 
    print('Exiting... Cancelling all tasks') 
    tasks.cancel() # or f1.cancel(); f2.cancel() 
    print('Cancellation is done!') 

    loop.run_forever() 
    tasks.exception() # To skip '_GatheringFuture exception was never retrieved' warning 
finally: 
    loop.close() 

run_until_complete이 모든 작업을 마무리 (또는 취소) 후 루프를 중지 내부 콜백을 추가합니다

조금 더 좋은 방법은 loop.run_until_complete() 접근 방식을 사용하는 것입니다.

관련 문제