2016-09-14 1 views
2

В моем приложении Python GAE следующий фрагмент кода МНОГО медленнее в производстве, чем при локальном запуске. Обработка выполняется следующим образом:GAE Python код МНОГО медленнее в производстве, чем локально

  1. В POST загружается текстовый файл объемом около 1 МБ. Каждая строка текстового файла является «элементом».
  2. Мой код создает список элементов из текстового файла и проверяет наличие дубликатов и достоверность (путем сравнения с скомпилированным RE).

Вот код:

def process_items(self, text): 
    item_list = text.split() 
    item_set = set() 
    n_valid = 0 
    n_invalid = 0 
    n_dups = 0 
    out = "" 
    for item in item_list: 
     if item in item_set: 
      n_dups += 1 
      out += "DUPLICATE: %s\n" % item 
     elif valid_item(item): # This compares against a compiled RE 
      item_set.add(item) 
      n_valid += 1 
      out += "%s\n" % item 
     else: 
      n_invalid += 1 
      out += "INVALID: %s\n" % item 
    return out 

Когда я запускаю это на локальном сервере Dev, 1Мб файл 50000 строк занимает 5 секунд, чтобы обработать.

Когда я запускаю это в процессе производства, тот же файл занимает минуту, а запрос истекает. Загрузка файла занимает всего около секунды, поэтому я знаю, что шея бутылки - это код выше.

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

Любая идея, почему этот код сейчас намного медленнее в производстве? Что-нибудь, что я могу сделать, чтобы сделать этот код быстрее? Мне нужно вернуть аннотированный файл пользователю, который указывает, какие строки являются дубликатами и какие строки недействительны.

EDIT:

В ответ на комментарий mgilson, я попытался следующий код, и он сделал огромную разницу во времени исполнения! Обработка, которая ранее была отключена через минуту, занимает всего около 5 секунд. GAE все еще медленнее, чем ожидалось (даже учитывая относительно медленные серверные процессоры), но с улучшенным алгоритмом для меня это не имеет значения.

def process_items(self, text): 
    item_list = text.split() 
    item_set = set() 
    n_valid = 0 
    n_invalid = 0 
    n_dups = 0 
    for i, item in enumerate(item_list): 
     item = item.strip() 
     if item in item_set: 
      n_dups += 1 
      item_list[i] = "DUPLICATE: %s" % item 
     elif valid_item(item): # This compares against a compiled RE 
      item_set.add(item) 
      n_valid += 1 
      item_list[i] = item 
     else: 
      n_invalid += 1 
      item_list[i] = "INVALID: %s" % item 
    return "\n".join(item_list) 
+4

Сравнивая локальный ход и работает на GAE не очень справедливо. В зависимости от вашего набора [класс экземпляра] (https://cloud.google.com/appengine/docs/about-the-standard-environment#instance_classes) у вас может быть предел процессора до 600 МГц. Большинство персональных компьютеров _significantly_ быстрее, чем сейчас. Одна сразу очевидная оптимизация, что _might_ help заключается в том, чтобы накапливать результаты в списке и «возвращать» «.join (results)» в конце, а не использовать '+ ='. См. [Почему «.join() быстрее, чем + = в Python?] (Http://stackoverflow.com/q/39312099/748858), например ... – mgilson

+0

Создание' process_items' генератора 'yielding' одной строки в то же время ускорит его общее время обработки, устраняя медленный '+ =' –

+0

@mgilson, My Mac - 2,2 ГГц, поэтому он в 3,7 раза быстрее, чем GAE. Для этого кода на Python мой Mac по крайней мере на 12 раз быстрее, чем GAE. Это все еще кажется большим несоответствием, хотя я понимаю, что многие факторы делают его несовершенным сравнением. –

ответ

4

Это не совсем неожиданным, что производство GAE будет работать медленнее, чем на местном уровне - в зависимости от вашего instance class, производственной CPU может быть задушил цене 600MHz, которая значительно медленнее, чем большинство компьютеров разработчиков.

Одна вещь, вы можете сделать, чтобы ускорить процесс, чтобы накапливать ваши результаты в виде списка (или выход их из генератора), а затем использовать str.join, чтобы получить полный результат:

def process_items(self, text): 
    item_list = text.split() 
    item_set = set() 
    n_valid = 0 
    n_invalid = 0 
    n_dups = 0 
    out = [] 
    for item in item_list: 
     if item in item_set: 
      n_dups += 1 
      out.append("DUPLICATE: %s\n" % item) 
     elif valid_item(item): # This compares against a compiled RE 
      item_set.add(item) 
      n_valid += 1 
      out.append("%s\n" % item) 
     else: 
      n_invalid += 1 
      out.append("INVALID: %s\n" % item) 
    return "".join(out) 
Смежные вопросы