-1

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

由于页面加载时间是最终用户感知网站质量的重要因素,因此我试图减少加载可能不必要的模块的影响 - 特别是尝试减少初始化全局变量所需的时间(和内存)可能根本不需要。

简单地说,我的目标是:

  1. 尽可能减少模块初始化时间(不是 CPU 使用率)。
  2. 减少不需要的全局变量占用的内存。

为了说明,这是一个简单的模块示例:

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'

使用 Python 2.7,我得到了这些时间(最好的是没有范围的钩子):

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
4

1 回答 1

1

导入语句执行模块,因此您不应该四处更改其语义。

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

全局变量也是如此——将它们变成类静态变量或其他东西。无论如何,拥有很多全局变量是不好的风格。

但为什么这甚至是一个问题?您是否真的包含了这么多模块而只是发现它们会减慢速度,或者某些包含的包进行了大量昂贵的初始化(例如,打开连接)?我的钱在第二个。如果您编写了负责减速的模块,请考虑将初始化包装到适当的构造函数中。

于 2012-03-05T17:31:11.350 回答