开发者

Google App Engine singletons (Python)

The standard way of doing singletons in Python is开发者_JAVA百科

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

However, this doesn't work on App Engine, since there are may be many servers and we would get one instance per server. So how would we do it for an app engine entity?

Something like:

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)

This leads to a recusion error, since get() calls __init__.

How we're going to use it:

We just want to represent a configuration file, ie:

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


Singletons are usually a bad idea, and I'd be interested to see what makes this an exception. Typically they're just globals in disguise, and apart from all the old problems with globals (eg. see http://c2.com/cgi/wiki?GlobalVariablesAreBad, in particular the bit at the top talking about non-locality, implicit coupling, concurrency issues, and testing and confinement), in the modern world you get additional problems caused by distributed and concurrent systems. If your app is potentially running across multiple servers, can you meaningfully have both instances of your application operate on the same singleton instance both safely and correctly?

If the object has no state of its, then the answer is yes, but you don't need a singleton, just a namespace.

But if the object does have some state, you need to worry about how the two application instances are going to keep the details synchronised. If two instances try reading and then writing to the same instance concurrently then your results are likely to be wrong. (eg. A HitCounter singleton that reads the current value, adds 1, and writes the current value, can miss hits this way - and that's about the least damaging example I can think of.)

I am largely unfamiliar with it, so perhaps Google App Engine has some transactional logic to handle all this for you, but that presumably means you'll have to add some extra stuff in to deal with rollbacks and the like.

So my basic advice would be to see if you can rewrite the algorithm or system without resorting to using a singleton.


If you aren't going to store the data in the datastore, why don't you just create a module with variables instead of a db.Model?

Name your file mysettings.py and inside it write:

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

Then the python module effectively becomes a "singleton". You can even add functions, if needed. To use it, you do something like this:

import mysettings
print mysettings.sitename

That's how django deals with this with their DJANGO_SETTINGS_MODULE

Update: It sounds like you really want to use a db.Model, but use memcached so you only retrieve one object once. But you'll have to come up with a way to flush it when you change data, or have it have a timeout so that it gets get'd occasionally. I'd probably go with the timeout version and do something like this in 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

Or, if you don't want to use memcache, then just store the object in a module level variable and always use the Settings() function to reference it. But then you'll have to implement a way to flush it until the interpreter instance is recycled. I would normally use memcached for this sort of functionality.


__init__ cannot usefully return anything: just like in the first example, override __new__ instead!


I don't think there's a real "singleton" object you can hold in a distributed environment with multiple instances running. The closest you can come to this is using memcache.

Perhaps it's better to think less in terms of singletons and more in terms of data consistency. For this App Engine provides transactions, which allow you to trap any changes in an entity that might happen while you're working with that entity.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜