首页 > 解决方案 > 导入给定模块的所有功能与仅导入我们需要的那些功能之间的内存和性能差异是什么?

问题描述

例如 import math 在数学模块中导入的所有功能,而如果我们编写 from math import sqrt,pow 则只sqrt(),pow()被导入。

他们两者的任何性能或内存差异。

标签: pythonpython-3.xperformancememory-management

解决方案


例如import math在数学模块中导入的所有功能,而如果我们编写from math import sqrt,pow则只sqrt(),pow()被导入。

比这复杂一点。

如果我们暂时忽略math解释器中内置的(因此实际上不需要加载任何内容),无论您是否执行或import math,无论如何都会加载整个模块,并且在 import 语句之后,它存在于. 因此,根据您导入的方式,加载工作并没有或多或少的工作要做。from math import sqrt, powfrom math import *mathsys.modules

这些构造之间的唯一区别是在导入范围内创建对您在导入语句中提到的名称的引用。

import math本身可能是最便宜的语句,因为它加载模块并只是在当前范围内添加对模块对象的本地引用;它基本上归结为做

math = __import__('math')

但是,每次使用都会更加昂贵,因为如果是在全局范围内,math.sin则需要两个 dict 查找(一个LOAD_GLOBAL和一个) ,或者一个局部变量查找()+一个 dict 查找()(如果它是在本地导入到function) 来实际到达要调用的函数对象。LOAD_ATTRimportLOAD_FASTLOAD_ATTR

from math import sqrt, pow将花费更多,因为它需要加载模块,查找sqrtpow在其中(两个字典查找)并在导入它们的范围内创建相应的条目(如果在全局范围内,则两个字典分配,STORE_FAST如果在功能范围)。它相当于:

__temp = __import__('math')
sqrt = __temp.sqrt
pow = __temp.pow
del __temp

__temp实际上并不存在,它将只是堆栈上的一个对象;sqrt并且pow将是局部变量或全局变量,具体取决于import发出语句的位置)

另一方面,在查找时这会更快,因为与上述两个相比,它只需要一个 dict 查找(LOAD_GLOBAL用于全局导入)或一个本地查找(用于导入本地到函数)。LOAD_FAST

from math import *与上述相同,但针对模块__all__列表中提供的所有符号(或模块周期提供的所有符号,如果未__all__指定)。

从内存的角度来看,后两个将比第一个花费更多,因为它们在本地列表或全局字典中创建了更多条目。

话虽如此,这种考虑通常是完全无关的,因为我们谈论的是极小的差异;在决定如何导入时,最重要的是允许以较少输入/较少显式导入的名义对命名空间造成多少污染。

相反,在这些问题上通常很重要的优化是将经常调用的函数绑定到局部变量,以避免在内部循环中连续查找;例如

import math

def plot_it(framebuffer):
    sin = math.sin
    cos = math.cos
    for y in range(1024):
        for x in range(1024):
            framebuffer[y][x] = int(127*(sin(x)+cos(2*y)))

通常会比做math.sinmath.cos在每次迭代时更快,甚至比在文件的顶层导入sin和直接在循环内使用它们要快,因为它们分别是两个或一个字典查找(在每次迭代中完成) cos,而这里的解释器只需要在内部循环中加载两个本地变量(这非常快,它只是一个直接的数组加载)。


推荐阅读