2014-10-17 1 views
0

Я экспериментировал с Python 2.7 и Tornado 3.2. Я пытался получить простой сопрограмму пример работать, но без особого везения:Не могу получить повышение Вернуться к работе при использовании сопрограммы

import tornado.web 
from tornado.gen import coroutine 
from tornado.httpclient import AsyncHTTPClient 
from tornado.gen import Return 

class MainHandler(tornado.web.RequestHandler): 

    # Tried with and without @asynchronous 
    @tornado.web.asynchronous 
    def get(self): 
      data = MainService().get_google_data() 
      self.write(data) 


class MainService: 

    @coroutine 
    def get_google_data(self): 
      response = yield AsyncHTTPClient().fetch("http://www.google.com") 
      raise Return(value = 'hello') 

Я ожидал, что это будет выписывать «привет», когда керлинг URL. Вместо этого, я получаю:

... 
File "/vagrant/venv/lib/python2.7/site-packages/tornado/web.py", line 656, in write 
raise TypeError("write() only accepts bytes, unicode, and dict objects") 
TypeError: write() only accepts bytes, unicode, and dict objects 

По-видимому, будущее возвращается, но называть result() на будущее бросает еще одно исключение: DummyFuture does not support blocking for results

Торнадо документы говорят, что для того, чтобы вернуть значение из сопрограммы, вы получаете исключение возврата. Рассматривая исходный код, это действительно похоже на то, что ожидается. Тем не менее, когда я запускаю его, он, похоже, не работает.

Оцените это!

+0

Копаем глубже в Runner.run(), я чувствую, что, возможно, перешел к выводам о том, что это делает. – MrSilverSnorkel

+0

Как в стороне, вы можете просто «поднять Return ('hello») '. Нет необходимости в 'value ='. – dano

+0

@ dano Да, значение = было просто без уважительной причины. Копая в Бегун, я вижу теперь, что он не совсем делает то, что, как я думал, на первый взгляд. Он возвращает будущее, которое, как я думаю, вы говорили в своем ответе. – MrSilverSnorkel

ответ

4

Вы должны yield вызова get_google_data():

class MainHandler(tornado.web.RequestHandler): 

    @coroutine 
    def get(self): 
     data = yield MainService().get_google_data() 
     self.write(data) 

Торнадо сопрограмма всегда возвращает Future. Вы ждете результата этого Future, позвонив по телефону yield. Без yield вы просто получите сразу Future, не дожидаясь завершения сопрограммы. Вы также должны использовать декоратор @coroutine по методу get, в дополнение к get_google_data. Декоратор @asynchronous обычно используется, если вы хотите использовать обратные вызовы, а не сопрограммы.

+0

Да, это имеет смысл. Поэтому, если у меня есть обработчик, который вызывает службу, которая вызывает объект доступа к данным, а объект доступа к данным реализует сопрограмму, все вызовы, которые находятся в стеке, должны уступать и быть украшены сопрограммами? – MrSilverSnorkel

+0

@MrSilverSnorkel Yep, сопрограммы «вирусные», как правило. Как только вы добавите его, все, что его называет, тоже хочет стать одним. Существуют способы вызова сопрограммы, не имея при этом контекста вызова, также являющегося сопрограммой, но ее немного более clunkier, чем просто «yield coroutine_call()». – dano

+0

спасибо, вы дали мне пищу для размышлений. Не могли бы вы указать мне на пример одного из этих способов вызова сопрограммы, не имея вызывающего контекста, является сопрограммой? – MrSilverSnorkel

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