2012-03-28 4 views
0

в моем приложении i для одного из обработчиков мне нужно получить кучу сущностей и выполнить функцию для каждого из них.Выполнение параллельного кода python2.7 ndb

У меня есть ключи от всех тех, которые мне нужны. после извлечения их мне нужно выполнить 1 или 2 метода экземпляра для каждого из них, и это немного замедляет мое приложение. выполнение этого для 100 объектов занимает около 10 секунд, что является способом замедления.

im пытается найти способ получить объекты и выполнять эти функции параллельно, чтобы сэкономить время, но я не уверен, какой путь является лучшим.

Я попробовал _post_get_hook, но у меня есть будущий объект, и мне нужно вызвать get_result() и выполнить функцию в hook, которая работает вроде ok в sdk, но получает много «максимальной глубины рекурсии», Python objec ', но я не могу понять, почему и сообщение об ошибке не очень сложное.

- это трубопровод api или ndb.Tasklets, что искал?

atm im собирается проб и ошибок, но я был бы счастлив, если бы кто-то мог привести меня в правильном направлении.

EDIT

мой код что-то похожее на файловую систему, каждая папка содержит другие папки и файлы. Путь Коллекций, установленный на другой объект, чтобы сериализовать объект коллекции, мне нужно получить связанный объект и получить путь. В коллекции функция 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]) 

это тасклет код нормально?

+0

Являются ли функции медленными, потому что они выполняют много вычислений или потому, что они ждут RPC? Если первое, нить или задача - ваш лучший выбор; если последний, то талисман NDB - это то, что вы хотите.Разработайте, и я могу опубликовать ответ, демонстрирующий один из них. –

+0

@NickJohnson в основном его ждет RPC. Я отредактировал вопрос с более подробной информацией. – aschmid00

ответ

2

Поскольку большая часть времени выполнения ваших функций расходуется на ожидание RPC, поддержка Async и Tasklet NDB - ваш лучший выбор. Это описано подробно 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, чтобы сделать их асинхронно), возвращая результат, когда это будет сделано. Поскольку обратный вызов является тасклетом и использует выход для асинхронных вызовов, NDB может запускать несколько экземпляров его параллельно и даже запускать некоторые операции.

+0

Я не думаю, что могу использовать карту, потому что я использую ndb.get_multi() в списке ключей, которые я уже знаю (или, по крайней мере, я не видел каких-либо документов об использовании карты с ndb.get_multi()). – aschmid00

+0

Я думаю, что есть несколько опечаток или, может быть, старые документы: ndb.get_async (msg.author) должен быть msg.author.get_async() и tasket.Return is ndb.Return ...?! – aschmid00

+0

acct - это объект Future, поэтому попытка форматирования строки в Return возвращает AttributeError: объект 'Future' не имеет атрибута 'nick' – aschmid00

0

API-интерфейс трубопровода является излишним для того, что вы хотите сделать. Есть ли причина, по которой вы не можете просто использовать задание?

Используйте начальный запрос, чтобы получить все ключи сущностей, а затем запустите задачу для каждого ключа, у которого задача выполняет 2 функции для каждого объекта. Параллелизм будет основываться на количестве одновременных запросов, настроенных для этой задачи.