在GAE中实现请求级别的全局变量
2009 10 22 04:49 PM 2236次查看
分类:Google App Engine 标签:Google App Engine, Python
GAE文档里提到了handler cache和module cache,这2种缓存实际上是将main函数所在环境(包括模块的载入)缓存在1个Python实例里,使相邻较近的请求可以重用该Python实例。
该Python实例经测试至少存在30秒,一般可维持1分钟,过期后随时可能会被系统回收。
当用户发出请求时,GAE服务器会优先使用活动的Python实例去响应,若不存在活动或空闲的Python实例,且未超过单一app的实例上限(约30个),则GAE服务器会创建一个新的Python实例去响应。
因此,重用Python实例时,它的全局变量和模块内的变量是可以跨请求重用的;而各个Python实例间,则不能共享相同的环境及其全局变量。
若要实现一个请求内的全局变量,最简单的办法是在全局环境里创建一个变量,在main()函数开始时赋值,响应结束时清空。
这种方法的效率很高,但必须在主handler里提前创建所需的变量(也可以是一个字典对象),且在响应结束时可能因抛出异常而忘记清空,导致下一次响应可能会使用错误的值。
最重要的缺点是跨模块时,获取__main__里的全局变量并不方便。我的方法是把全局变量放在一个module里,然后需要用到它的就去import。
另一种方法是使用os.environ,这个对象在每次响应时由服务器进行设置,所以不会出现跨响应的情况。它的使用类似一个字典对象,但key和value都必须是字符串(且key一般是大写)。
下面这个简单的脚本就演示了如何统计响应所用时间:
from os import environ
from time import time
from google.appengine.ext import webapp
from wsgiref.handlers import CGIHandler
class MainPage(webapp.RequestHandler):
def get(self):
self.response.out.write(repr(time() - float(environ['TIME'])))
# 对于webapp来说,由于它重用了webob的request对象,所以写成self.request.environ['TIME']也是可以的
# 而web.py则可以用web.ctx.env.get('TIME')
application = webapp.WSGIApplication([('/', MainPage)])
def main():
environ['TIME'] = repr(time())
CGIHandler().run(application)
if __name__ == "__main__":
main()
注意这里不适合用clock(),在GAE服务器上,它的精度只有约0.01秒,无法进行毫秒级的统计,所以我用了精度更高的time()。不过clock()可以得出该Python实例共用了多少CPU时间(跨请求的)。此外,系统的启动时间及输出的时间并未计算在内,所以并不能精确地提供响应时间。
另外,google.appengine.api.quota模块则可用于计算CPU和API CPU时间。
使用第2种方法,就可以方便地记录一次响应中,数据库、memcache的使用次数及其开销了,这也是我研究它的初衷。当然最好是自己再稍微封装一下这个实现,实现自动计时。
向下滚动可载入更多评论,或者点这里禁止自动加载。