python - 使用 Python 在 Google App Engine 中的应用启动时加载全局可访问的单例

标签 python google-app-engine

使用 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/

相关文章:

java - python 相当于 java RSAIO.save

java - GAE/J 范围查询中最大可能的键字符串是什么?

google-app-engine - 我可以在 Google App Engine 上构建邮件列表软件吗?

python - 用句子增量训练 Sklearn 的 SGD 分类器

python - 向 Buildbot 添加自定义功能

java - 具有 JPA 部署的 Google App Engine 应用程序挂起

java - FinalizationException - AppEngine Java Blobstore API

javascript - 在 Web 应用程序中使用时保护 Cloud Endpoint(限制来源?)

python - Django admin - 使所有字段只读

python:检查一个键中一定数量的字符是否与同一字典中另一个键的字符匹配