2017-01-04 96 views
0

我正在使用裝飾器使用@gen.coroutine裝飾器來處理GET請求的異步協程的Python3 tornado Web服務器。我想用這個功能從庫:Python生成器和減少

@gen.coroutine 
def foo(x): 
    yield do_something(x) 

這是很簡單的:

@gen.coroutine 
def get(self): 
    x = self.some_parameter 
    yield response(foo(x)) 

現在假設有多個功能foo1foo2,相同類型的等等。我想要做一些類似...foo3(foo2(foo1(x).result()).result())...yield的方法,而不是get方法中的response(foo(x))

我認爲這將很容易與reduceresult方法。但是,由於tornado的工作原理,我不能強制fooresult方法返回某些內容。這意味着yield reduce(...)提供了一個錯誤:「DummyFuture不支持結果阻塞」。從SO和其他地方的答案,我知道我將不得不使用IOLoop什麼的,我聽不太懂,並...

...我的問題是,我怎麼能避免評估所有foo syield那個從get方法未評估塊?

編輯:這不是this question重複的,因爲我想:1巢很多功能和2.儘量不立即評估。

+0

的可能的複製[不能調用在龍捲風期貨的結果()] (http://stackoverflow.com/questions/31172272/cant-call-result-on-futures-in-tornado) – Natecat

+0

如果你的意思是返回一個模擬該嵌套的函數(-like)對象,那麼[this](http ://stackoverflow.com/questions/15331726/how-does-the-functools-partial-work-in-python)是合適的重複 – Natecat

回答

1

在Tornado中,您必須使用yield a協議才能得到結果。評論Tornado's coroutine guide

你可以編寫一個協程的reducer。它運行的每個協程得到一個未來,呼籲yield與未來得到一個結果,然後運行該結果對下一個協程:

from tornado.ioloop import IOLoop 
from tornado import gen 


@gen.coroutine 
def f(x): 
    # Just to prove we're really a coroutine. 
    yield gen.sleep(1) 
    return x * 2 


@gen.coroutine 
def g(x): 
    return x + 1 


@gen.coroutine 
def h(): 
    return 10 


@gen.coroutine 
def coreduce(*funcs): 
    # Start by calling last function in list. 
    result = yield funcs[-1]() 

    # Call remaining functions. 
    for func in reversed(funcs[:-1]): 
     result = yield func(result) 

    return result 


# Wrap in lambda to satisfy your requirement, to 
# NOT evaluate immediately. 
latent_result = lambda: coreduce(f, g, h) 
final_result = IOLoop.current().run_sync(latent_result) 
print(final_result) 
+0

謝謝,這是有道理的。你能解釋一下在coreduce函數內發生多重yield和return語句的情況嗎? – shardulc

+1

每個「yield」等待被調用的協程完成,並解決Future返回結果。 「return」語句從協程返回一個值。不管協程回報如何成爲它未來的價值。 –

+0

「協程的回報成爲它未來的價值」:這是迄今爲止關於協程的最有用的陳述。非常感謝你! – shardulc