Google app engine 如何避免Python模块全局初始化的延迟?

Google app engine 如何避免Python模块全局初始化的延迟?,google-app-engine,optimization,python,lazy-initialization,Google App Engine,Optimization,Python,Lazy Initialization,我试图优化用python编写的web应用程序的一般加载时间。我的应用程序使用了很多模块,其中一些模块对于给定的请求可能是需要的,也可能不是 由于页面加载时间是最终用户感知的站点质量的一个重要因素,因此我正在尝试减少加载可能不必要的模块的影响,尤其是尝试减少初始化可能根本不需要的全局模块所需的时间(和内存) 简言之,我的目标是: 尽可能减少模块初始化时间(而不是CPU使用) 要减少不需要的全局变量占用的内存 下面是一个简单的模块示例: COMMON = set(('alice', 'has', '

我试图优化用python编写的web应用程序的一般加载时间。我的应用程序使用了很多模块,其中一些模块对于给定的请求可能是需要的,也可能不是

由于页面加载时间是最终用户感知的站点质量的一个重要因素,因此我正在尝试减少加载可能不必要的模块的影响,尤其是尝试减少初始化可能根本不需要的全局模块所需的时间(和内存)

简言之,我的目标是:

  • 尽可能减少模块初始化时间(而不是CPU使用)
  • 减少不需要的全局变量占用的内存
  • 下面是一个简单的模块示例:

    COMMON = set(('alice', 'has', 'cat', 'with', 'blue', 'eyes'))
    
    COMMON
    构建集合需要时间-如果不使用
    COMMON
    ,那将浪费加载时间和内存。
    显然,对于单个模块/全局模块,成本可以忽略不计,但是如果您有100个模块和100个变量怎么办

    使其更快的一种方法是延迟初始化,如下所示:

    __cache_common = None
    def getCommon():
        global __cache_common
        # not use before
        if __cache_common is None:
            __cache_common = set(('alice', 'has', 'cat', 'with', 'blue', 'eyes'))
        # get cached value
        return __cache_common
    
    它节省了加载时间和内存,牺牲了一些CPU

    我尝试了一些其他的技术(见下文),其中两种比上面简单的缓存快一点

    我是否可以使用另一种技术来进一步缩短可能无法用于给定请求的模块和全局模块的加载时间?


    到目前为止,我尝试过的方法需要Python 2.6+:

    from timeit import Timer
    
    __repeat = 1000000
    __cache = None
    
    def getCache():
        return __cache
    
    def getCacheTest():
        for i in range(__repeat):
            getCache()
    
    def getLocal():
        return set(('alice', 'has', 'cat', 'with', 'blue', 'eyes'))
    
    def getLocalTest():
        for i in range(__repeat):
            getLocal()
    
    def getLazyIf():
        global __cache
        if __cache is None:
            __cache = getLocal()
        return __cache
    
    def getLazyIfTest():
        for i in range(__repeat):
            getLazyIf()
    
    def __realLazy():
        return __cache
    
    def getLazyDynamic():
        global __cache, getLazyDynamic
        __cache = getLocal()
        getLazyDynamic = __realLazy
        return __cache
    
    def getLazyDynamicTest():
        for i in range(__repeat):
            getLazyDynamic()
    
    def getLazyDynamic2():
        global __cache, getLazyDynamic2
        __cache = getLocal()
        def __realLazy2():
            return __cache
        getLazyDynamic2 = __realLazy2
        return __cache
    
    def getLazyDynamic2Test():
        for i in range(__repeat):
            getLazyDynamic2()
    
    print sum(Timer(getCacheTest).repeat(3, 1)), getCacheTest, 'raw access'
    print sum(Timer(getLocalTest).repeat(3, 1)), getLocalTest, 'repeat'
    print sum(Timer(getLazyIfTest).repeat(3, 1)), getLazyIfTest, 'conditional'
    print sum(Timer(getLazyDynamicTest).repeat(3, 1)), getLazyDynamicTest, 'hook'
    print sum(Timer(getLazyDynamic2Test).repeat(3, 1)), getLazyDynamic2Test, 'scope hook'
    
    使用Python2.7,我得到了以下时间安排(最好是没有范围的hook):

    1.01902420559原始访问
    5.40701374057重复
    1.39493902158有条件
    1.06692051643吊钩
    1.15909591862范围钩
    
    导入语句执行模块,因此您不应该到处更改其语义

    把import语句塞进需要它们的函数或方法中怎么样?这样,它们只会在需要时发生,而不会在应用程序启动时发生

    全局变量也是如此——将它们转换为类静态或其他类型。不管怎么说,有很多全球人是不好的风格


    但为什么这甚至是一个问题呢?您是否真的包含了太多的模块,仅仅查找它们就会减慢速度,或者所包含的一些包是否进行了大量昂贵的初始化(例如,打开连接)?我的钱在第二条上。如果您已经编写了导致速度减慢的模块,请考虑将初始化包装到适当的构造函数中。

    可行,但如果通常这样做,这是一种可怕的做法-如果所有导入都分散在整个文件中,则会使代码更难理解;另一面是依赖项的封装。例如,了解所有sql交互都限制在单个模块中,也有助于理解代码。或者在使用bletch之前查看foo import bletch中的
    。无论如何,你可以半途而废:稍微封装导入,但不是封装到每个函数和方法中——我有点夸张了。这不是导入模块的最佳解决方案,模块用于频繁函数,但它适用于单调用函数(很简单)。模块中的全局变量并没有“那么糟糕”,因为每个模块都是分开的。由于我是一名经验丰富的程序员,所以我不会像globals那样进行泛化,因为globals是不好的。如果没有分离(即,在Basic中),那么这是真的-无论每个对象也有“globals”,它更分离,但仍然是共享的。请记住,python实际上不会重新读取已经加载的模块。后续导入是一个简单的字典查找。我仍然和你们在一起,我不愿意把“导入re”放在一个紧密的循环中。也许只是迷信。
    
    1.01902420559 <function getCacheTest at 0x012AE170> raw access
    5.40701374057 <function getLocalTest at 0x012AE1F0> repeat
    1.39493902158 <function getLazyIfTest at 0x012AE270> conditional
    1.06692051643 <function getLazyDynamicTest at 0x012AE330> hook
    1.15909591862 <function getLazyDynamic2Test at 0x012AE3B0> scope hook