单例的替代方案?
我刚开始学习Python和App Engine(还有服务器端的东西),现在想做一个非常简单的内容管理系统(CMS)。每次部署这个应用时,都会有一个公司对象,只会有一个,创建这个对象的方式大概是这样的:
class Company(db.Model):
name = db.StringPropery()
profile = db.TextProperty()
addr = db.TextProperty()
我想提供一个功能,可以更新公司的资料和其他细节。
我最开始的想法是创建一个公司实体的单例(也就是只创建一个实例)。不过我看了一下(虽然还没完全理解)这个讨论,感觉这样做很难,而且不太建议。
所以我想,也许在每次部署CMS的时候,我可以运行一个脚本(通过一个很难找到的URL触发),这个脚本简单地创建一个公司对象。之后,我就可以用theCompany = Company.all()[0]
来获取这个实例。
这样做可以吗?
然后我记得在那个讨论里,有人建议直接使用一个模块。所以我创建了一个Company.py文件,把一些变量放进去。我在SDK里试了试,结果发现它能正常工作——让我惊讶的是,修改过的变量值在请求之间“存活”了下来。
请原谅我的无知,我想这些值只是保存在内存中,而不是存储在磁盘上——和数据存储的东西不一样?这样做稳妥吗?(而且这些模块变量在我应用的所有脚本调用中都能用吗?)
3 个回答
我觉得你看到的方法是最简单的:
- 使用模块变量,初始值设为
None
。 - 为这些变量提供访问方法(获取和设置)。
- 当你访问一个变量时,如果它的值是 None,就从数据库中获取它。否则,直接使用这个值。
这样一来,你就能在整个应用中使用这些由模块提供的变量(它们不会被反复创建),这些变量会被共享,你也不会丢失它们。
听起来你想让你的应用程序可以根据不同的应用进行配置。
为什么不使用数据存储来保存你的公司信息,并给它一个唯一的名字呢?这样你就总能知道怎么获取公司的信息,而且可以在不重新部署的情况下编辑这些信息。
company = Company(key_name='c')
# set stuff on company....
company.put()
# later in code...
company = Company.get_by_key_name('c')
可以使用 memcache 来存储公司的详细信息,这样就可以避免重复访问数据存储。
除了使用memcache,你还可以用模块变量来缓存这些值。正如你所看到的,这些值在请求之间是 被缓存 的。
全局变量是“应用缓存”的。这意味着你应用的每个实例会在请求之间记住这些变量的值。不过,当一个实例关闭时,这些值就会丢失。所以我觉得你不应该把这些值存储在模块级的变量里(除非它们是一些不需要更新的常量)。
我认为你最初的解决方案是可以的。你甚至可以使用“远程API”工具来创建最初的实体,这样你就不需要一个复杂的页面来实例化唯一的Company
对象。
如果你通过键来获取这个单例Company
实体,可以让这个过程更快一些。
如果你需要频繁获取这个实体,可以使用缓存技术来避免多次访问数据存储。最快的方法是在你从数据存储获取Company
实体后,将其应用缓存。为了防止实体变得过时,你还可以缓存你最后一次获取实体的时间,如果这个时间超过N秒,你就可以从数据存储重新获取它。想了解更多关于这个选项以及它与其他方法的比较,可以查看Nick Johnson的文章App Engine上的存储选项。