2016-07-02 2 views
2

Только что начал экспериментировать с асинхронным, который выглядит действительно круто. Я пытаюсь использовать фьючерсы с асинхронная сопрограммы, который работает вечно, но я получаю эту ошибку:Python с использованием фьючерсов с loop_forever

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. Например:

@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() 

BTW, вы можете использовать новый синтаксис (async, await), если вы используете Python 3.5+:

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

Очень круто. Спасибо. Но теперь я нахожусь на стадии запроса, зачем нам нужны фьючерсы? Могу ли я вызвать регулярную функцию из courotine или именно поэтому future.set_result? необходим? – dpetican

+0

@dpetican, Извините, я не могу ответить на это. Как насчет отправки отдельного вопроса? – falsetru

+0

Короткий ответ: это зависит от того, нужна ли вам функция для асинхронности. – dirn

1

После @falsetru ответа это полная программа который имеет 3 асинхронных сопрограммы, каждый со своей собственной функцией get_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() 
Смежные вопросы