并行代码执行python2.7 ndb

时间:2012-03-28 20:39:35

标签: google-app-engine python-2.7 app-engine-ndb

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

我拥有所需的所有礼物的钥匙。在获取它们之后,我需要为它们中的每一个执行1或2个实例方法,这会使我的应用程序减慢很多。为100个实体执行此操作需要大约10秒,这是缓慢的方式。

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

我尝试了_post_get_hook,但我有一个未来的对象,需要调用get_result()并在钩子中执行该函数,这在sdk中运行良好,但在调用Python时会获得大量的超出最大递归深度objec'但我不能真正理解为什么和错误信息不是真的很复杂。

是我正在搜索的管道api或ndb.Tasklets吗?

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

修改

我的代码类似于文件系统,每个文件夹都包含其他文件夹和文件。集合的路径在另一个实体上设置,以便序列化集合实体,我需要获取引用的实体并获取路径。在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

EDIT2:

    @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代码好吗?

2 个答案:

答案 0 :(得分:2)

由于函数的大部分执行时间都花在等待RPC上,因此NDB的异步和tasklet支持是你最好的选择。这已经详细描述了here。您需求的最简单用法可能是使用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可以并行运行它的多个实例,甚至批处理一些操作。

答案 1 :(得分:0)

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

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