2016-12-06 2 views
0

Скажем, у меня есть эта функция асинхронного (Python 3,5)Как вернуть значение из сопрограммы, запущенной с помощью IOLoop от Tornado?

async def func(): 
    return '42' 

У меня есть цикл Tornado I/O, и я ищу способ, чтобы выполнить его.

import tornado.ioloop 

ioloop = tornado.ioloop.IOLoop.current() 
ioloop.start() 

Я мог бы просто использовать IOLoop.add_callback(func), но мне нужно возвращать значение, а также.
Любые идеи о том, что необходимо для получения возвращаемого значения?

РЕДАКТИРОВАТЬ
Метод func сопрограммы фактически принимает строку и отправляет его на сервер, получение ответа, распаковке ее должным образом и возвращать кортеж данных.
Он вызывается из обычного (неасинхронного) метода, который собирает строку на основе ее аргументов и должен получать ответ и возвращать данные вызывающему.
петля IO является переменной класса (доступны с self.)

Вот пример:

def register(self, arg1, arg2): 
    # process args here 

    ret_value = self.ioloop.add_callback(func, arg1, arg2) 
    # The above line is incorrect code, just for the idea 

    return ret_value 

ВТОРОЙ EDIT
Это часть кода, который бросает AssertionError:

async def _send(self, arg1): 
    self.ws.write_message(arg1) 
    resp = await self.ws.read_message() 
    return resp 

def callback(self, future): 
    print('future', future.result()) 

def register(self, arg1): 
    future = self._send(arg1) 
    self.ioloop.add_future(future, self.callback) 

Я начал выполнение register с использованием PeriodicCallback в классе __init__ способ.
в методе register Переменная future содержит <coroutine object Client._send at 0xb652c41c> и is_future проверки будет проходить только в том случае, что дано в будущем является экземпляром concurrent.futures.Future или tornado.concurrent.Future

ответ

0

Два варианта: сделать register сопрограмму или получить возвращаемое значение func в обратном вызове.

Вариант один:

async def register(self, arg1, arg2): 
    ret_value = await func(arg1, arg2) 
    return ret_value 

Вариант два:

def callback(future): 
    try: 
     ret_value = future.result() 
     # Do something with ret_value here. 
    except Exception as exc: 
     # Log the exception or something. 
     print(exc) 

def register(self, arg1, arg2): 
    future = func(arg1, arg2) 
    self.ioloop.add_future(future, callback) 

Вариант два неудобно, очевидно, потому что вы не можете использовать ret_value в оригинальной register функции. Я бы выбрал один вариант, сделав register сопрограммой. Тогда вызывающий абонент register также должен быть сопрограммой, вплоть до стека вызовов.

Это железный закон асинхронного программирования: для связи по сети ваша функция должна быть сопрограммой, которая выполняет yield или await, или вы должны зарегистрировать обратный вызов и выйти из текущей функции.

+0

Но 'run_sync' останавливает цикл событий, и это не совсем то, что я хочу. Функция 'func' в фактическом коде должна быть регулярным процессом, поэтому остановка цикла события не является опцией. – Leva7

+0

Можете ли вы рассказать о другом вопросе? Как вы называете 'func' и что вы хотите сделать с его возвращаемым значением? –

+0

Я уточнил вопрос с дополнительной информацией – Leva7