使用 Google 应用引擎,是否可以在应用启动时初始化全局可访问的单例?我有一个很大的静态树结构,我需要在每个请求上使用它,并且想事先初始化它。树结构太大 (20+MB) 无法放入 Memcache,我正在尝试找出其他替代方案。
编辑:只是为了根据我目前收到的答案增加一些清晰度。我正在将单词字典加载到 trie/prefix 树结构中。 trie 是不可变的,因为单词字典是固定的。我正在根据输入的字符串生成变位词,因此一个请求可能会在单个请求中访问相当数量的 trie,可能超过 1MB,但我不确定。
这是我正在加载单词字典的 python 结构。
class Node(object):
def __init__(self, letter='', final=False):
self.letter = letter
self.final = final
self.children = {}
def add(self, letters):
node = self
for index, letter in enumerate(letters):
if letter not in node.children:
node.children[letter] = Node(letter, index==len(letters)-1)
node = node.children[letter]
最佳答案
每个请求可能由完全不同的进程提供,在不同的服务器上,甚至可能在单独的数据中心(嘿,也许在不同的大陆)。除了数据存储之外,没有任何东西可以保证对同一应用程序的不同请求的处理程序“全局可访问”(如果事情变得太忙,即使内存缓存的条目也可能随时消失:它是一个缓存,毕竟!-)。
也许您可以将“静态树结构”保存在与应用程序代码一起上传的数据文件中,并从磁盘访问它而不是“初始化”。
编辑:根据要求,这是我在评论中提到的“轻量级类映射树到数组”方法的一个粗略且现成的示例——没有调整也没有经过精细测试。我以具有整数有效负载的二叉搜索树为例,并假设出于某种原因,在“轻”树中保持准确的结构与其代表的“重”树中的结构一样重要。即使进行了这些简化,代码仍然很多,但是,这里是:
import array
import random
def _doinsert(tree, payload):
if tree is None: return HeavyTree(payload)
tree.insert(payload)
return tree
class HeavyTree(object):
def __init__(self, payload):
self.payload = payload
self.left = self.right = None
def insert(self, other):
if other <= self.payload:
self.left = _doinsert(self.left, other)
else:
self.right = _doinsert(self.right, other)
def walk(self):
if self.left:
for x in self.left.walk(): yield x
yield self.payload
if self.right:
for x in self.right.walk(): yield x
def walknodes(self):
yield self
if self.left:
for x in self.left.walknodes(): yield x
if self.right:
for x in self.right.walknodes(): yield x
data = [random.randint(0, 99) for _ in range(9)]
print 'data: ',
for x in data: print x,
print
theiter = iter(data)
thetree = HeavyTree(next(theiter))
for x in theiter: thetree.insert(x)
print
print 'Heavy tree:'
print 'nodes:',
for x in thetree.walknodes(): print x.payload,
print
print 'inord:',
for x in thetree.walk(): print x,
print
class LightTree(HeavyTree):
def __init__(self, base, offset):
self.base = base
self.offset = offset
@property
def payload(self):
return self.base[self.offset]
@property
def left(self):
return self._astree(self.offset+1)
@property
def right(self):
return self._astree(self.offset+2)
def _astree(self, i):
offset = self.base[i]
if offset < 0: return None
return LightTree(self.base, offset)
def heavy_to_light(heavy):
for i, node in enumerate(heavy.walknodes()):
node.id = i * 3
base = array.array('l', (i+1) * 3 * [-1])
for node in heavy.walknodes():
base[node.id] = node.payload
if node.left: base[node.id+1] = node.left.id
if node.right: base[node.id+2] = node.right.id
return LightTree(base, 0)
print
print 'Light tree:'
light = heavy_to_light(thetree)
print 'nodes:',
for x in light.walknodes(): print x.payload,
print
print 'base :',
for x in light.base: print x,
print
print 'inord:',
for x in light.walk(): print x,
print
典型的运行会显示:
data: 27 79 90 60 82 80 3 94 76
Heavy tree:
nodes: 27 3 79 60 76 90 82 80 94
inord: 3 27 60 76 79 80 82 90 94
Light tree:
nodes: 27 3 79 60 76 90 82 80 94
base : 27 3 6 3 -1 -1 79 9 15 60 -1 12 76 -1 -1 90 18 24 82 21 -1 80 -1 -1 94 -1 -1
inord: 3 27 60 76 79 80 82 90 94
当然,每次的细节都是可变的,因为数据是随机生成的。
也许这种事情对于那些没有从良好的旧 Fortran 开始的人来说太麻烦了(因此不可避免地学会了如何将逻辑指针表示为数组的索引),就像我几十年前在电子工程学校所做的那样;-).但是将这样的数组从文件直接加载到内存中是非常快(与 unpickling 等相比)......!-)
关于python - 使用 Python 在 Google App Engine 中的应用启动时加载全局可访问的单例,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3050463/