微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

Twisted Deferred模式可保护未初始化的数据库

如何解决Twisted Deferred模式可保护未初始化的数据库

如何保护数据库在初始化之前不被访问?

我有一个数据库。需要初始化。这可能会花费一些时间,因此初始化会返回Deferred。我们称其为延迟的d_db_ready

我还有其他方法,例如read_a_value_from_the_database(),该方法仅在初始化数据库之后才想访问数据库

容易!我向d_db_ready添加了回调:

d_value = d_db_ready.addCallback(read_a_value_from_the_database)

现在,可以从延迟的d_value中找到我希望从数据库中获得的值。

让我们再次尝试:

d_value2 = d_db_ready.addCallback(read_a_value_from_the_database)

这一次不起作用。这是因为d_db_ready的回调链现在以我们从数据库中读取的值结尾。它不再提供对数据库的访问。

此处应使用哪种模式?我应该如何保护数据库在初始化之前不被访问?

read_a_value_from_the_database一个选项是返回数据库...但是这样就不会返回值。此外,这种方法一定程度上导致了潜在的潜在错误:当我忘记返回数据库时,我将不得不追查先前调用函数,而当我只剩下当前正在调用函数时。 / p>

下面是一些可运行的代码来演示我的问题:

from twisted.internet.defer import Deferred

database = "uninitialized"

d_db_ready = Deferred()

def init_database():
    global database
    print("Initializing database")
    database = { "value": 1 }
    d_db_ready.callback(database)

def read_a_value_from_the_database(db):
    value = db["value"]
    print("value:",value)
    return value

d_db_ready.addCallback(read_a_value_from_the_database)

d_db_ready.addCallback(read_a_value_from_the_database) # <--- errors

init_database()

解决方法

在数据库准备就绪之前,您所显示的模式已经很好地防止了数据库的使用。它的问题是它不支持多种用途。第二个回调不会失败,因为它具有未初始化的数据库。它只会在初始化数据库后失败,因为它会获得先前操作的结果而不是数据库的结果。

有两个常见选项。一种是停止具有多种用途。这并不听起来那么荒谬。例如:

def main():
    ...
    d_db_ready.addCallback(run_the_program)
    ...

def run_the_program(database):
    d_a = read_a_value_from_the_database(database)
    d_b = read_a_value_from_the_database(database)
    ...

现在d_db_ready上唯一的回调是run_the_programrun_the_program负责将数据库传递到需要去的地方。

第二个选项是使您的就绪API支持多种用途。您可以在此处采用多种不同的实现方法,但它们都以打破Deferred的结果链接功能为中心。例如,您可以这样做:

def wait_for_db(callback):
    def safe_callback(database):
        try:
            callback(database)
        except:
            # logging or support an errback or something
        return database
    d_db_ready.addCallback(safe_callback)

safe_callback确保d_db_ready的结果始终是数据库,而不是某些随机回调的结果。

可能有更好的实现此想法的方法(例如,仍然基于Deferred的实现,而不是放弃传递裸露的回调的能力)。希望这个简单的方法可以使您大致了解。

,

基于@ Jean-PaulCalderone回答中的第二个选项,这是基于Deferreds的实现:

def get_database():
    d = Deferred()
    def when_ready(db):
        d.callback(db)
        return db
    d_db_ready.addCallback(when_ready)
    
    return d

get_database().addCallback(read_a_value_from_the_database)
get_database().addCallback(read_a_value_from_the_database) # <--- works correctly

init_database()

请注意,d_db_ready现在应该被认为是功能get_database()的专用,并且不再应由用户访问。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。