0

在我的应用程序中,对于一个处理程序,我需要获取一堆实体并为每个实体执行一个函数。

我有我需要的所有实体的钥匙。获取它们后,我需要为它们中的每一个执行 1 或 2 个实例方法,这会大大降低我的应用程序的速度。对 100 个实体执行此操作大约需要 10 秒,这很慢。

我试图找到一种方法来获取实体并并行执行这些功能以节省时间,但我不确定哪种方法最好。

我尝试了 _post_get_hook 但我有一个未来的对象,需要调用 get_result() 并执行钩子中的函数,该函数在 sdk 中工作正常,但得到很多“调用 Python 对象时超出最大递归深度”但是我真的不明白为什么,错误信息也不是很详细。

Pipeline api 或 ndb.Tasklets 我在寻找什么?

atm 我正在反复试验,但如果有人能引导我走向正确的方向,我会很高兴。

编辑

我的代码类似于文件系统,每个文件夹都包含其他文件夹和文件。集合的路径设置在另一个实体上,因此要序列化集合实体,我需要获取引用的实体并获取路径。在 Collection 上, serialized_assets() 函数包含的实体越多,它的速度就越慢。如果我可以并排为每个包含的资产执行序列化函数,它会加快速度。

class Index(ndb.Model):
    path = ndb.StringProperty()


class Folder(ndb.Model):
    label = ndb.StringProperty()
    index = ndb.KeyProperty()

    # contents is a list of keys of contaied Folders and Files
    contents = ndb.StringProperty(repeated=True)    

    def serialized_assets(self):
        assets = ndb.get_multi(self.contents)

        serialized_assets = []
        for a in assets:
            kind = a._get_kind()
            assetdict = a.to_dict()
            if kind == 'Collection':
                assetdict['path'] = asset.path
                # other operations ...
            elif kind == 'File':
                assetdict['another_prop'] = asset.another_property
                # ...
            serialized_assets.append(assetdict)

        return serialized_assets

    @property
    def path(self):
        return self.index.get().path


class File(ndb.Model):
    filename = ndb.StringProperty()
    # other properties....

    @property
    def another_property(self):
        # compute something here
        return computed_property

编辑2:

    @ndb.tasklet
    def serialized_assets(self, keys=None):
        assets = yield ndb.get_multi_async(keys)
        raise ndb.Return([asset.serialized for asset in assets])

这个tasklet代码可以吗?

4

2 回答 2

2

由于你的函数的大部分执行时间都花在等待 RPC 上,NDB 的 async 和 tasklet 支持是你最好的选择。这在此处进行了详细描述。根据您的要求,最简单的用法可能是使用该ndb.map函数,如下所示(来自文档):

@ndb.tasklet
def callback(msg):
  acct = yield ndb.get_async(msg.author)
  raise tasklet.Return('On %s, %s wrote:\n%s' % (msg.when, acct.nick(), msg.body))

qry = Messages.query().order(-Message.when)
outputs = qry.map(callback, limit=20)
for output in outputs:
  print output

为查询返回的每个实体调用回调函数,它可以执行它需要的任何操作(使用_async方法并yield异步执行它们),完成后返回结果。因为回调是一个tasklet,并且使用yield来进行异步调用,NDB可以并行运行它的多个实例,甚至可以批处理一些操作。

于 2012-03-29T14:06:57.683 回答
0

管道 API 对于您想要做的事情来说太过分了。你有什么理由不能只使用任务队列吗?

使用初始请求获取所有实体键,然后为每个键排队一个任务,让该任务执行每个实体的 2 个功能。并发将基于为该任务队列配置的并发请求数。

于 2012-03-29T07:35:09.433 回答