3

Я использую Google Appengine с Python 2.5, и у меня есть функция, которая вызывает узкое место. Я передаю ему список из 200 экземпляров модели, извлеченных из хранилища данных, и возвращает его в формате json, который затем передаю клиенту.String Concatenation Python 2.5 (using cStringIO)

Первоначально я использовал + =, чтобы объединить все значения вместе, но серверу потребовалось около 30 секунд, чтобы сервер ответил JSON. Я проверил некоторые проверки и код до того, как эта функция заработает менее секунды. Это последнее заявление перед тем, как сервер отвечает JSON и время, необходимое для достижения средних значений клиента за 1 секунду (в моей локальной сети). Эта функция занимает в среднем 30 секунд для выполнения.

Я прочитал это article и попытался с помощью метода cStringIO (я также использовал этот список метода присоединиться, но он принял такое же количество времени и cStringIO использует меньше памяти, так что я застрял с ним). Однако это заняло примерно то же время, что и + = конкатенация (иногда дольше). Может ли кто-нибудь увидеть какие-либо проблемы с моим кодом, которые могут сделать его медленнее?

EDIT: Босс говорит, что это должно быть сделано таким образом. Нет json-библиотек (возьмите его с собой).

EDIT 2: LastName Модель:

class LastName(db.Model): 
    entry = db.ReferenceProperty(AlumniEntry, collection_name='last_names') 
    last_name = db.StringProperty(indexed=False) 
    last_name_search = db.StringProperty() 

AlumniEntry является Model, что запрашивается. Я передаю список, который я возвращаюсь из ds в get_json_from_alumnus() (параметр alumnus).

def get_json_from_alumnus(alumnus, search, total=0): 
    if len(alumnus) > 0: 
     from cStringIO import StringIO 
     concat_file = StringIO() 

     concat_file.write('{ "alumnus": [') 
     i = 0 
     for alumni in alumnus: 
      if alumni.author: 
       author = alumni.author.nickname() 
      else: 
       author = 'Anonymous' 

      concat_file.write('{ ') 
      concat_file.write('"author": "') 
      concat_file.write(author) 
      concat_file.write('", ') 
      concat_file.write('"title": "') 
      concat_file.write(alumni.title) 
      concat_file.write('", ') 
      concat_file.write('"first_name": "') 
      concat_file.write(alumni.first_name) 
      concat_file.write('", ') 

      concat_file.write(' "last_names": [') 
      j = 0 
      for lname in alumni.last_names: 
       concat_file.write('{ "last_name": "') 
       concat_file.write('lname.last_name') 
       concat_file.write('" }') 
       if not j == alumni.last_names.count() - 1: 
        #last_names += ',' 
        concat_file.write(',') 
       j +=1 
      concat_file.write('], ') 

      concat_file.write(' "addresses": [') 
      j = 0 
      for address in alumni.addresses: 
       if address.street == '' and address.city == '' and address.state == '' and address.zip_code == '': 
        break 

       concat_file.write('{ "address":{ "street" : "') 
       concat_file.write(address.street) 
       concat_file.write('", ') 
       concat_file.write('"city" : "') 
       concat_file.write(address.city) 
       concat_file.write('", ') 
       concat_file.write('"state" : "') 
       concat_file.write(address.state) 
       concat_file.write('", ') 
       concat_file.write('"zip_code" : "') 
       concat_file.write(address.zip_code) 
       concat_file.write('" } }') 

       if not j == alumni.addresses.count() - 1: 
        concat_file.write(',') 
       j += 1 
      concat_file.write('], ') 

      concat_file.write(' "numbers": [') 
      j = 0 
      for phone_number in alumni.phone_numbers: 
       concat_file.write('{ "phone_number": "') 
       concat_file.write(phone_number.number) 
       concat_file.write('" }') 
       if not j == alumni.phone_numbers.count() - 1: 
        concat_file.write(',') 
       j += 1 
      concat_file.write('], ') 

      concat_file.write(' "emails": [') 
      j = 0 
      for email in alumni.emails: 
       concat_file.write('{ "email": "') 
       concat_file.write(email.email) 
       concat_file.write('" }') 
       if not j == alumni.emails.count() - 1: 
        concat_file.write(',') 
       j += 1 
      concat_file.write('], ') 

      concat_file.write('"grad_year": "') 
      concat_file.write(alumni.grad_year) 
      concat_file.write('", ') 
      concat_file.write('"elementary": "') 
      concat_file.write(alumni.elementary) 
      concat_file.write('", ') 
      concat_file.write('"entered": "') 
      concat_file.write(str(alumni.entered.strftime('%B %d %Y'))) 
      concat_file.write('", ') 
      concat_file.write('"key": "') 
      concat_file.write(str(alumni.key())) 
      concat_file.write('" ') 
      concat_file.write('}') 

      if not i == len(alumnus) - 1: 
       concat_file.write(',') 
      i += 1 
     concat_file.write('], "total" : "') 
     concat_file.write(str(total)) 
     concat_file.write('" }') 
    else: 
     concat_file.write('{ "alumnus": "No Alumni Entered Yet!" }' if not search else '{ "alumnus": "No Matches!" }') 

    return concat_file.getvalue() 
+3

Я действительно, действительно, действительно, действительно должен знать: почему вы не используете simplejson? –

+0

Босс говорит, ничего простого. Я не делаю правила, но я следую им. В любом случае у меня такая же проблема с другой функцией, где мне нужно объединить CSV-файл вместе, но он не был столь же насущным, как этот. – Eliezer

+1

* вздох * simplejson поймает все проблемы, которые ваш код испортит. –

ответ

7

Я подозреваю, что эта строка в коде:

if not j == alumni.last_names.count() - 1: 

(и несколько подобных строк).

Вы не разместили свою модель, но мне кажется, что alumni.last_names может быть запросом? Выполнение запроса для каждого объекта было бы очень плохой идеей и могло бы очень сильно повлиять на ваши затраты. CStringIO не должно занимать около 30 секунд, чтобы объединить несколько тысяч строк.

Легко узнать, если вы выполняете слишком много запросов с помощью Appstats: http://code.google.com/appengine/docs/python/tools/appstats.html (вы даже можете попробовать это на сервере разработчиков dev).

PS. Единственное на самом деле является выпускником, а множественное число - выпускниками. :-)

+0

См. Edit 2 для моей модели LastName. Я просто подумал, что это может быть проблемой. Я никогда не думал об этом раньше, но я предполагаю, что это другой запрос (или получить). Это был недостаток дизайна, который, как я думал, был исправлен, но, видимо, это не так. Я попробую еще раз с другой структурой модели. Благодаря тонну! – Eliezer

+0

Что касается выпускников выпускников вещь ... половина нашего кода имеет это в одну сторону, а половина - в другую сторону. Не уверен точно, как это произошло, но это полная катастрофа :) – Eliezer

2

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

Для получения дополнительной информации, пожалуйста, обратитесь к этому related question.

Редактировать: Если использование стороннего модуля json не может быть и речи, я бы попытался уменьшить количество звонков write с использованием строки форматирования как можно дольше.

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

+0

спасибо, но смотри править – Eliezer

+1

Модуль JSON недоступен на Python 2.5, и в любом случае интерпретатор AppEngine не может загружать модули Python с помощью кода C: это «чистая» среда Python. –

+0

@Paolo: GAE running 2.5 явно делает доступным simplejson. –

5

str.join() и интерполяция строк обычно дают много лучше, чем повторное конкатенация. Дайте им попробовать, и пусть силы, которые будут помиловать вашу душу.

+0

Принимал такое же количество времени. Я не думал, что это так много данных, но возможно ли, что это потолок python для обработки этого количества строк? Я работаю на безумно мощной и оптимизированной машине, поэтому это не должно быть мое оборудование (на самом деле он работает быстрее на сервере appengine, чем на моем devserver). Я попробовал метод simplejson для себя, и это было довольно быстро. Если вы положите это в ответ, я соглашусь с ним, если у кого-то нет техники конкатенации, которая будет удовлетворительной. – Eliezer

 Смежные вопросы

  • Нет связанных вопросов^_^