2016-07-02 7 views
2

ちょうど本当にクールに見えるasynchで実験を始めました。私は永遠に走る非同期のコルーチンで先物を使用しようとしているが、私はこのエラーを取得:loop_foreverで未来を使うPython

Task exception was never retrieved 
future: <Task finished coro=<slow_operation() done, defined at ./asynchio-test3.py:5> exception=InvalidStateError("FINISHED: <Future finished result='This is the future!'>",)> 

これは予想通り、私は先物に関連する3行を削除した場合に実行される私のコードです:

import asyncio 

@asyncio.coroutine 
def slow_operation(): 
    yield from asyncio.sleep(1) 
    print ("This is the task!") 
    future.set_result('This is the future!') 
    asyncio.async(slow_operation()) 

def got_result(future): 
    print(future.result()) 

loop = asyncio.get_event_loop() 
future = asyncio.Future() 
future.add_done_callback(got_result) 
asyncio.async(slow_operation()) 
try: 
    loop.run_forever() 
finally: 
    loop.close() 

答えて

2

slow_operatorが無期限に呼び出され、同じ将来のオブジェクトに対して複数回呼び出されるset_result。それは可能性がありません。

>>> import asyncio 
>>> future = asyncio.Future() 
>>> future.set_result('result') 
>>> future.set_result('result') 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "C:\Python35\lib\asyncio\futures.py", line 329, in set_result 
    raise InvalidStateError('{}: {!r}'.format(self._state, self)) 
asyncio.futures.InvalidStateError: FINISHED: <Future finished result='result'> 

slow_operatorコールごとに新しい未来を作成してください。たとえば:あなたは、Python 3.5+を使用している場合

@asyncio.coroutine 
def slow_operation(future): 
    yield from asyncio.sleep(1) 
    print ("This is the task!") 
    future.set_result('This is the future!') 
    asyncio.async(slow_operation(new_future())) 

def got_result(future): 
    print(future.result()) 

def new_future(): 
    future = asyncio.Future() 
    future.add_done_callback(got_result) 
    return future 

loop = asyncio.get_event_loop() 
asyncio.async(slow_operation(new_future())) 
try: 
    loop.run_forever() 
finally: 
    loop.close() 

ところで、あなたは新しい構文(asyncawait)を使用することができます。

async def slow_operation(future): 
    await asyncio.sleep(1) 
    print ("This is the task!") 
    future.set_result('This is the future!') 
    asyncio.ensure_future(slow_operation(new_future())) 
+0

非常にクールです。ありがとうございました。しかし、私は今、なぜ先物が必要なのか尋ねる段階にあります。私はクロトーネから通常の機能を呼び出すことができますか、それはなぜfuture.set_resultですか?必要ですか? – dpetican

+0

@dpetican、申し訳ありませんが、私はそれに答えることはできません。別の質問を投稿するのはどうですか? – falsetru

+0

短い答えは、関数が非同期である必要があるかどうかによって異なります。 – dirn

1

これは完全なプログラムで答える@falsetru後それぞれ3つの非同期コルーチンがあり、それぞれに独自のgot_result関数があります。私はv3.4を使用していますので、なぜ私は新しい構文を使用しません。興味深い副作用として、出力はコルーチンのシングルスレッドの性質を明確に示しています。私はそれが誰かのためのテンプレートとして役立つことを願っています:

import asyncio 

@asyncio.coroutine 
def task1(future): 
    yield from asyncio.sleep(1) 
    print ("This is operation#1") 
    future.set_result('This is the result of operation #1!') 
    asyncio.async(task1(new_future(got_result1))) 

def got_result1(future): 
    print(future.result()) 

@asyncio.coroutine 
def task2(future): 
    yield from asyncio.sleep(1) 
    print ("This is operation#2") 
    future.set_result('This is the result of operation #2!') 
    asyncio.async(task2(new_future(got_result2))) 

def got_result2(future): 
    print(future.result()) 

@asyncio.coroutine 
def task3(future): 
    yield from asyncio.sleep(1) 
    print ("This is operation#3") 
    future.set_result('This is the result of operation #3!') 
    asyncio.async(task3(new_future(got_result3))) 

def got_result3(future): 
    print(future.result()) 

def new_future(callback): 
    future = asyncio.Future() 
    future.add_done_callback(callback) 
    return future 

tasks = [task1(new_future(got_result1)), 
     task2(new_future(got_result2)), 
     task3(new_future(got_result3))] 

loop = asyncio.get_event_loop() 
for task in tasks: 
    asyncio.async(task) 

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