2012-04-13 2 views
1

У меня есть задание cron AppEngine, которое запрашивает хранилище данных, а затем нужно выполнить некоторую работу над каждым объектом, возвращаемым запросом. Ожидается, что количество объектов, возвращаемых запросом, будет иногда большим (> 1000).Можно ли использовать qry.map_async(), когда количество результатов запроса велико?

Моя цель - максимизировать параллелизм, а также поддерживать низкий уровень использования памяти - поскольку ожидаемое количество результатов велико, они могут не соответствовать памяти.

Учитывая большое # результатов, я должен перебрать их так:

qry = Model.query() 
qit = qry.iter() 
while (yield qit.has_next_async()): 
    entity = qit.next() 
    # Do something with entity 

... или это безопасно использовать быстрее map_async() работать на сколь угодно большом наборе результатов?

@ndb.tasklet 
def callback(entity): 
    # Do something with entity 

qry = Model.query() 
yield qry.map_async(callback) 

Я прочитал все документы и даже посмотрел на кишках реализации, и это не совсем ясно, что ограничения этих операций для больших наборов результатов.

+1

Использование «yield something_async()» не является чем-то большим, чем использование синхронного API, если ваш код не запущен в тасклете (в этом случае он все равно не будет работать быстрее, но другие вещи могут работать на одном и том же время). –

+0

Кроме того, «> 1000» покрывает много. Это> 10 000? > 100000? > 1000000? В какой-то момент лучший подход меняется. –

+0

Hi Nick, да мой код запущен в тасклете, и я понимаю, что это не совсем «быстрее», а позволяет одновременно запускать другие тасклеты. Спасибо за разъяснения. Что касается числа сущностей, я ожидаю, что число будет выше, чем, возможно, 10 000. –

ответ

5

Карта считывает пакет одновременно, а затем вызывает обратный вызов для каждого объекта в пакете. Так что все должно быть хорошо. Вы можете поэкспериментировать с размером партии.

Разница заключается в том, что сам обратный вызов делает больше ввода-вывода. Тогда версия for loop предположительно ожидает, что каждый элемент будет полностью обработан, в то время как карта только начинает все обратные вызовы и только ждет их в самом конце. Таким образом, больше параллелизма, бот также потенциально больше использует память.

+0

Я реализовал это задание cron, используя реализацию map_async внутри таска. Запрос, который я просматриваю, обычно имеет 1000 или более результатов. После успешного завершения 300 обратных вызовов я получаю ошибку истечения срока действия запроса: «Запрошенный запрос истек. Пожалуйста, перезапустите его с последним курсором, чтобы узнать больше результатов». Любые предложения о том, что я должен делать? Возможно, перейдете к курсорам? Следует отметить, что каждый обратный вызов, в свою очередь, делает map_async для разных объектов (обычно между 1 и 3 сущностями) для каждого внешнего результата запроса. –

+0

Я ожидаю, что разбивка запроса на «страницы», например. 100 объектов, связанных курсорами, решают это. Сообщение об ошибке возникает из-за несоответствия между временем жизни активного запроса (думаю, 30 секунд) и временем вашего задания cron (на самом деле запросом очереди задач) (10 минут). И поскольку, как вы говорите, вы выполняете много работы для каждого обратного вызова, вы долго обрабатываете весь запрос. Параллелизм, введенный map(), в любом случае ограничен размером пакета, и если у вас слишком много выдающихся RPC, вы все равно будете дросселироваться. –