我们有以下代码示例:
big_static_data = {
"key1" : {
"subkey1" : "subvalue1",
...
},
"key2" :
...
}
class StaticDataEarlyLoad:
def __init__(self):
self.static_data = big_static_data
# other init
def handle_use_id(self, id):
return complex_handle(self.static_data, id)
...
class StaticDataLazyLoad:
def __init__(self):
# not init static data
# other init
def handle_use_id(self, id):
return complex_handle(big_static_data, id)
...
正如上面的代码所说,每当我们调用实例的 handle_use_id 时,我们可能会遇到不同的性能问题。
IMO,早期加载将在创建实例时加载数据,并且将在内存中直到实例被吞噬。对于后期加载,在我们调用 handle_use_id 方法之前,不会加载静态数据。 我是对的吗?(因为我对Python的内部不太清楚,我不确定该实例将持续多长时间才会被打开)。如果我是对的,早期加载意味着大内存需求,后期加载意味着每次调用方法时我们都必须加载数据(这是一个很大的开销?)
现在,我们是一个基于网络的项目,那么应该被选为最佳方法?( handle_use_id 将会非常频繁地调用。)
感谢。
答案 0 :(得分:3)
在您的示例中,StaticDataLazyLoad(一旦 init 的语法正确)将不会产生重大影响。
导入模块时,“big_static_data”被初始化(“加载”)。无论是否创建了类的实例,它都会立即需要一些内存。
StaticDataEarlyLoad的实例只会创建对big_static_data的新引用,而不是新副本。
因此,StaticDataEarlyLoad中的查找可能会稍快一些,因为数据是通过本地范围内的self引用的(查找“self”,然后查找“self.static_data”)。
StaticDataLazyLoad中的查找在本地范围内找不到“big_static_data”,然后python将在全局范围内查找并找到它。由于全局范围可能更大,因此查找可能需要比查找“self.static_data”更长的时间。
答案 1 :(得分:3)
big_static_data在文件开头创建一次(至少在您显示的代码中)。
这消耗了记忆。
创建StaticDataEarlyLoad的实例时,
StaticDataEarlyLoad()。static_data是对big_static_data的引用。 它消耗的内存非常少。它只指向big_static_data指向的相同字典。没有big_static_data的副本,没有真正的“加载”。
当实例StaticDataEarlyLoad()被垃圾收集时,会释放一些内存,但big_static_data仍然存在。
StaticDataLazyLoad做了很多相同的事情,但没有创建属性static_data
。它只是直接引用big_static_data。 StaticDataEarlyLoad和StaticDataLazyLoad之间的内存消耗差异非常小。并且速度基本上没有差异。
最好明确表达课程所依赖的内容。
StaticDataEarlyLoad
取决于big_static_data。
因此,您应该定义
class StaticDataEarlyLoad:
def __init__(self,static_data):
self.static_data = static_data
使用StaticDataEarlyLoad(big_static_data)
初始化实例。
此定义与您发布的定义之间的速度基本没有差异。将依赖项放入__init__
的调用签名中只是为了组织起了一个好主意,毕竟你使用Python的OOP来很好地控制组织,对吧?