我正在使用Google Appengine和Python 2.5,我有一个导致瓶颈的功能。我传递了一个从数据存储区检索到的200个模型实例的列表,然后以json格式返回它,然后传递给客户端。
我最初使用+ =将所有值连接在一起,但服务器用JSON响应需要大约30秒。我运行了一些检查和代码,然后在一秒钟内运行此函数。这是服务器响应JSON之前的最后一条语句,以及在1秒内(在我的本地网络上)达到客户端平均值所需的时间。此功能平均需要30秒才能执行。
我读了这个article并尝试使用cStringIO
方法(我也使用了列表连接方法,但它花了相同的时间,而cStringIO
使用的内存更少,所以我坚持使用它)。但是,这与+ =连接(有时更长)的时间大致相同。任何人都可以看到我的代码有任何问题,可能会让它变慢吗?
编辑:老板说必须这样做。没有json图书馆(与他一起接受)。
编辑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()
答案 0 :(得分: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 appserver中尝试这个)。
PS。单数实际上是校友,复数是校友。 : - )
答案 1 :(得分:5)
str.join()
和字符串插值通常比重复连接提供更多更好的性能。试试这些,并且可以怜悯你的灵魂。
答案 2 :(得分:2)
我建议您创建要在python本身作为答案发送的数据结构,并使用json模块生成字符串版本。这样做的原因是最流行的json模块至少部分用c实现,所以尽管{c}中也实现了cStringIO
,我猜他们只使用标准库很难实现一些优化。
有关详细信息,请参阅此related question。
编辑:如果使用第三方json模块是不可能的,那么我尝试尽可能使用格式化字符串来减少write
次调用次数。
我想使用一个可以提高速度的模板库也会被排除,所以我能想到的唯一方法就是尽可能地缓存,以便后续的调用不需要重做整个任务。