Google App Engine单例(Python)

时间:2010-01-12 04:59:46

标签: python google-app-engine singleton google-cloud-datastore

在Python中执行单例的标准方法是

class Singleton(object):
    _instance = None
    def __new__(cls, *args, **kwargs):
        if not cls._instance:
            cls._instance = super(Singleton, cls).__new__(cls, *args, **kwargs)
        return cls._instance

但是,这在App Engine上不起作用,因为可能有很多服务器,我们每个服务器会得到一个实例。那么我们如何为app引擎实体做呢?

类似的东西:

class MySingleton(db.models):
    def __init__(self):
        all = MySingleton.all()
        if all.count() > 0:
             return all.fetch(1).get()

        super(MySingleton, self).__init__ (*args, **kwargs)

由于get()调用了__init__

,这会导致重写错误

我们将如何使用

我们只想表示一个配置文件,即:

{ 'sitename': "My site", 'footer': "This page owned by X"}

4 个答案:

答案 0 :(得分:4)

单身人士通常是个坏主意,我有兴趣看看是什么让这个例外。通常它们只是伪装的全局变量,除了全局变量的所有旧问题之外(例如,见http://c2.com/cgi/wiki?GlobalVariablesAreBad,特别是顶部的位讨论非局部性,隐式耦合,并发问题,以及测试和限制),在现代世界中,您会遇到由分布式和并发系统引起的其他问题。如果您的应用程序可能跨多个服务器运行,那么您是否可以安全正确地在同一个单例实例上运行应用程序的两个实例?

如果对象没有它的状态,那么答案是肯定的,但你不需要单例,只需要命名空间。

但是如果对象确实有某种状态,则需要担心两个应用程序实例如何保持细节同步。如果两个实例尝试读取然后同时写入同一个实例,那么结果可能是错误的。 (例如,一个HitCounter单例,它读取当前值,加1,并写入当前值,可能会错过这样的命中 - 这就是我能想到的最不具破坏性的例子。)

我基本上不熟悉它,所以也许Google App Engine有一些交易逻辑可以为你处理所有这些,但这可能意味着你必须添加一些额外的东西来处理回滚等。

所以我的基本建议是看你是否可以在不使用单例的情况下重写算法或系统。

答案 1 :(得分:2)

如果您不打算将数据存储在数据存储区中,为什么不创建一个包含变量而不是db.Model的模块?

将文件命名为mysettings.py,并在其中写下:

sitename = "My site"
footer = "This page owned by X"

然后python模块实际上变成了“单例”。如果需要,您甚至可以添加功能。要使用它,你可以这样做:

import mysettings
print mysettings.sitename

这就是django用DJANGO_SETTINGS_MODULE

处理这个问题的方法

<强>更新: 听起来你真的想要使用db.Model,但是使用memcached,所以你只需要检索一个对象。但是你必须想出一种方法来在你更改数据时刷新它,或者让它有一个超时,以便偶尔得到它。我可能会使用超时版本并在mysettings.py中执行类似的操作:

from google.appengine.api import memcache
class MySettings(db.Model):
   # properties...

def Settings():
    key = "mysettings"
    obj = memcache.get(key)
    if obj is None:
       obj = MySettings.all().get()  # assume there is only one
       if obj:
            memcache.add(key, zone, 360)
       else:
            logging.error("no MySettings found, create one!")
    return obj

或者,如果您不想使用memcache,那么只需将对象存储在模块级变量中,并始终使用Settings()函数来引用它。但是,您必须实现一种方法来刷新它,直到解释器实例被回收。我通常会使用memcached来实现这种功能。

答案 2 :(得分:1)

__init__无法有效return任何内容:就像在第一个示例中一样,覆盖__new__而不是!

答案 3 :(得分:0)

我认为在一个运行多个实例的分布式环境中,你可以拥有一个真正的“单例”对象。你最接近的就是使用memcache。

或许最好在单身方面少考虑,在数据一致性方面考虑更多。对于此App Engine提供transactions,它允许您捕获在您使用该实体时可能发生的实体中的任何更改。