什么时候会在函数调用堆栈中实际产生收益?

时间:2015-09-02 15:16:54

标签: python tornado tornado-motor

我正在使用python 3.4.3中的龙卷风和电机。

我有三个文件。可以将其命名为main.pymodel.pycore.py

我有三个功能,每个功能一个......

main.py

def getLoggedIn(request_handler):
    # request_handler = tornado.web.RequestHandler()
    db = request_handler.settings["db"]
    uid = request_handler.get_secure_cookie("uid")
    result = model.Session.get(db, uid=uid)
    return result.get("_id", None) if result else None

model.py

@classmethod
    def get(cls, db, user_id=None, **kwargs):
        session = core.Session(db)
        return session.get(user_id, **kwargs)

core.py

@gen.coroutine
    def get(self, user_id, **kwargs):
        params = kwargs
        if user_id:
            params.update({"_id": ObjectId(user_id)}) #This does not exist in DB
        future = self.collection.find_one(params)
        print(future) #prints <tornado.concurrent.Future object at 0x04152A90>
        result = yield future
        print(result) #prints None
        return result

来电看起来像getLoggedIn =&gt; model.get =&gt; core.get

core.get以@gen.coroutine修饰,我致电yield self.collection.find_one(params) print(result)打印None,但如果我返回结果并尝试在getLoggedIn函数中打印返回值,则会打印出来。

我认为这与龙卷风的异步性质有关,而印刷品在收益前被调用,但我不确定。如果有人能够在不同的情况下解释协程/发电机的原理和行为,那将是一个很大的帮助。

2 个答案:

答案 0 :(得分:1)

PEP 255涵盖了生成器的原始规范。 但是,tornado以非常具体的方式在协同程序中使用yieldhttp://www.tornadoweb.org/en/stable/guide/coroutines.html#how-it-works

你的代码看起来并不像普通的生成器,因为生成器的Python概念正被tornado用来定义协同程序。 我会说你并不真正想要发电机编写的原则,而是龙卷风发电机的原理 - 一种完全不同的野兽。

分配yield的值是一种包装@gen.coroutine装饰器将未来结果传递回core.get的方法。 这样,result未分配未来对象,而是future.result()

yield future基本上会暂停你的函数并将其转换为future将调用的回调,并在yield的位置恢复执行。 正如您所担心的那样,tornado的异步性质不允许yieldprint之前运行。

最有可能的是,你的Future没有返回任何东西,或者正在返回None(语义等价,我知道)。 最好将result = yield future视为result = future.result()

的专用版本

答案 1 :(得分:0)

必须提供对协程的每次调用,并且调用者也必须是协程。所以getLoggedIn必须是一个调用的协程:

result = yield model.Session.get(db, uid=uid)

等等。有关详细示例和解释,请参阅我在refactoring Tornado coroutines上的文章。