2016-06-08 1 views
0

외부 작업 완료시 완료해야하는 작업 (하위 작업)이 있다고 가정 해 봅니다. 우리는 외부 작업을 제어 할 수 없습니다. 언제 완료 될지 (서브 작업이 완료되기 전에 발생할 수 있음) 우리는 내부의 서브 작업을 기다릴 수 없습니다.외부 작업 완료 이벤트 (외부 동기화 버전 add_done_callback)에서 보조 작업 완료 대기 중

import asyncio 


def create_sub_task(): 
    sub_task = asyncio.ensure_future(sub()) 
    # We want this sub_task to be finished when outer task done 


async def sub(): 
    await asyncio.sleep(2) 
    print('sub done') 


async def main(): # main is outer task for sub_task 
    create_sub_task() 
    await asyncio.sleep(1) 
    print('outer done') 


if __name__ == "__main__": 
    loop = asyncio.get_event_loop() 
    loop.run_until_complete(main()) 

add_done_callback는 외부 작업이 완료되면 순간을 잡을 수있는 방법처럼 보이지만, 우리는 여기에 하위 작업을 위해 기다릴 수 없어 : 외부 작업을 하위 작업 전에 완료 때문에 우리가 경고 얻을 것이다이 조각에서

: 이 기능은 동기식입니다. 내가 찾은

방법은 작업이 동 기적으로 콜백 안에 완료 기다려야 이벤트 루프의 개인 _run_once 기능을 사용하는 것입니다

import asyncio 
from functools import partial 


def create_sub_task(): 
    sub_task = asyncio.ensure_future(sub()) 

    # Callback to wait for sub_task 
    outer_task = asyncio.Task.current_task() 
    outer_task.add_done_callback(partial(_stop_task, sub_task)) 


async def sub(): 
    await asyncio.sleep(2) 
    print('sub done') 


def _stop_task(sub_task, task): 
    # Ugly way to wait sub_task finished: 
    loop = asyncio.get_event_loop() 
    while not sub_task.done(): 
     loop._run_once() 


async def main(): # main is outer task for sub_task 
    create_sub_task() 
    await asyncio.sleep(1) 
    print('outer done') 


if __name__ == "__main__": 
    loop = asyncio.get_event_loop() 
    loop.run_until_complete(main()) 

그것은 작동하지만, 여러 가지 문제 추한 방법입니다.

모든 아이디어를 어떻게 해결하는 것이 더 나은가요?

답변

1

AFAIK 내부적 인 문제없이이를 해결할 방법이 없습니다. 개인적으로 나는 나중에 asyncio.gather 외부 및 하위 작업을 수행 한 다음 콜백을 다시 작성합니다.

불행하게도 콜백 미래의 목록은 공용 인터페이스 (I가 _callbacks을 사용하고 있습니다)에 노출되지 않습니다

import asyncio 

def create_sub_task(): 
    sub_task = asyncio.ensure_future(sub()) 
    outer_task = asyncio.Task.current_task() 

    multi_fut = asyncio.gather(sub_task, outer_task) 
    for cb in outer_task._callbacks: 
     multi_fut.add_done_callback(cb) 
     outer_task.remove_done_callback(cb) 

async def sub(): 
    await asyncio.sleep(2) 
    print('sub done') 


async def main(): # main is outer task for sub_task 
    create_sub_task() 
    await asyncio.sleep(1) 
    print('outer done') 


if __name__ == "__main__": 
    loop = asyncio.get_event_loop() 
    loop.run_until_complete(main()) 

내가 원하는하지 않거나 흐름을 변경할 수 있다고 가정하지만 격려 너 다시 생각해 봐. 어쩌면 일부 컨텍스트 - 제한 조건 원본을 게시 할 수 있습니다.

+0

감사합니다. 원래 나는 문제의 비동기 생성기의 일종을 구현하려고 여기에 직면 http://stackoverflow.com/a/37572657/1113207 (코드의 초기 버전) "하위 작업"- 발전기의 시체입니다. 작업이 완료 될지 모르겠지만 외부 작업이 끝나면 작업을 중단해야합니다 ('_cleanup' 기능 참조). –