2016-09-01 9 views
1

Я прихожу из земли Twisted/Klein. Я пришел с миром и попросил помощь Tornado. Я изучаю Tornado и как его асинхронный подход отличается от Twisted. Витая есть что-то похожее на gen.coroutine, который defer.inlineCallbacks и я могу написать код асинхронной так:Итерация петли с ожиданием или выходом вызывает ошибку

kleinsample.py

@app.route('/endpoint/<int:n>') 
@defer.inlineCallbacks 
def myRoute(request, n): 
    jsonlist = [] 
    for i in range(n): 
     yield jsonlist.append({'id': i}) 
    return json.dumps(jsonlist) 

локон CMD:

curl localhost:9000/json/2000 

Эта конечная точка будет создайте строку JSON с числом элементов n. n может быть маленьким или очень большим. Я могу разбить его в Twisted, чтобы цикл событий не блокировал использование yield. Теперь вот, как я попытался преобразовать это в Торнадо:

tornadosample.py

async def get(self, n): 
    jsonlist = [] 
    for i in range(n): 
     await gen.Task(jsonlist.append, {'id': i}) # exception here 
    self.write(json.dumps(jsonlist)) 

отслеживающий:

TypeError: append() takes no keyword arguments 

Я смущен о том, что я должен сделать, чтобы правильно перебирать каждый элемент в цикле, чтобы цикл события не блокировался. Кто-нибудь знает способ «Торнадо» сделать это?

ответ

1

Вы не можете и не должны ждать append, так как это не сопрограмма и не возвращает Будущее. Если вы хотите иногда уступать, чтобы другие сопрограммы продолжали использовать цикл событий Tornado, ожидайте gen.moment.

from tornado import gen 

async def get(self, n): 
    jsonlist = [] 
    for i in range(n): 
     jsonlist.append({'id': i}) 
     if not i % 1000: # Yield control for a moment every 1k ops 
      await gen.moment 
    return json.dumps(jsonlist) 

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

+0

Я планировал сделать что-то похожее на ваш ответ (что-то вроде '' wait Future() ', а затем добавить). Надеемся найти лучшее решение, если не ваш ответ. Это не интенсивность процессора, но фактический код (который значительно сложнее, чем пример в моем сообщении) - это раздел, который блокирует достаточно, чтобы нарушить другие функции на моем текущем синхронном сайте. Поэтому мое желание * приостанавливать * итерирование на * момент * (все каламбуры предназначены). –

+0

Что будет «лучшим решением», чем то, что я разместил? С чем я могу вам помочь? –

+0

Извините, это не значит, что ваш ответ не был хорошим ответом. Я мог бы поклясться, что в последний раз, когда я использовал Tornado, была функция, которая позволяла мне передавать итерируемый или генератор, а затем асинхронно запускать обратные вызовы на элемент. У Twisted есть что-то, называемое Cooperator, которое может сделать что-то подобное, поэтому я подумал, что у Tornado есть аналогичное решение. Ваше решение должно быть в порядке для моих требований. –

0

Давайте посмотрим на gen.Taskdocs:

Адаптирует обратный вызов на основе асинхронной функции для использования в сопрограммах.

Выполняет функцию (и необязательные дополнительные аргументы) и запускает ее с этими аргументами плюс аргумент ключевого слова обратного вызова. Аргумент, переданный обратному вызову, возвращается в результате выражения yield.

Поскольку append не принимает ключевое слово аргумент, который не знает, что делать с этим callback kwarg и плюет это исключение.

Что вы можете сделать, это обернуть append с вашей собственной функции, которая делает принимать callback kwarg или подход показал в this ответ.

1

list.append() возвращает None, так что это немного вводит в заблуждение, что ваш образец Klein выглядит так, будто он дает некоторый объект.Это эквивалентно jsonlist.append(...); yield как два отдельных оператора. Эквивалент торнадо должен был бы сделать await gen.moment вместо голых yield.

Также обратите внимание, что обработчики обработали свои ответы, вызвав self.write(), а не возвращая значения, поэтому оператор return должен быть self.write(json.dumps(jsonlist)).

+0

Да, я понимаю, почему это вводит в заблуждение. Это не лучший фрагмент в мире, но он получил мою точку зрения (по крайней мере, я думал). Я забыл изменить '' return'' '' self.write', так как я написал этот пример на лету. Спасибо за уловку –

 Смежные вопросы

  • Нет связанных вопросов^_^