我正在编写一个辅助类来评估网格上的参数化函数。由于网格不会随参数改变,所以我选择将其一次性创建为类属性。
但是,我意识到将网格作为类属性与将其作为全局变量相比会导致性能显着下降。更有趣的是,二维网格的性能差异似乎在一维网格中消失了。
这是演示该问题的最小“工作”示例:
import numpy as np
import time
grid_1d_size = 25000000
grid_2d_size = 5000
x_min, x_max = 0, np.pi / 2
y_min, y_max = -np.pi / 4, np.pi / 4
# Grid evaluation (2D) with grid as class attribute
class GridEvaluation2DWithAttribute:
def __init__(self):
self.x_2d_values = np.linspace(x_min, x_max, grid_2d_size, dtype=np.float128)
self.y_2d_values = np.linspace(y_min, y_max, grid_2d_size, dtype=np.float128)
def grid_evaluate(self):
cost_values = np.cos(self.x_2d_values[:, None] * self.y_2d_values[None, :])
return cost_values
grid_eval_2d_attribute = GridEvaluation2DWithAttribute()
initial_time = time.process_time()
grid_eval_2d_attribute.grid_evaluate()
final_time = time.process_time()
print(f"2d grid, with grid as class attribute: {final_time - initial_time} seconds")
# Grid evaluation (1D) with grid as global variable
x_2d_values = np.linspace(x_min, x_max, grid_2d_size)
y_2d_values = np.linspace(y_min, y_max, grid_2d_size)
class GridEvaluation2DWithGlobal:
def __init__(self):
pass
def grid_evaluate(self):
cost_values = np.cos(x_2d_values[:, None] * y_2d_values[None, :])
return cost_values
grid_eval_2d_global = GridEvaluation2DWithGlobal()
initial_time = time.process_time()
grid_eval_2d_global.grid_evaluate()
final_time = time.process_time()
print(f"2d grid, with grid as global variable: {final_time - initial_time} seconds")
# Grid evaluation (1D) with grid as class attribute
class GridEvaluation1DWithAttribute:
def __init__(self):
self.x_1d_values = np.linspace(x_min, x_max, grid_1d_size, dtype=np.float128)
def grid_evaluate(self):
cost_values = np.cos(self.x_1d_values)
return cost_values
grid_eval_1d_attribute = GridEvaluation1DWithAttribute()
initial_time = time.process_time()
grid_eval_1d_attribute.grid_evaluate()
final_time = time.process_time()
print(f"1d grid, with grid as class attribute: {final_time - initial_time} seconds")
# Grid evaluation (1D) with grid as global variable
x_1d_values = np.linspace(x_min, x_max, grid_1d_size, dtype=np.float128)
class GridEvaluation1DWithGlobal:
def __init__(self):
pass
def grid_evaluate(self):
cost_values = np.cos(x_1d_values)
return cost_values
grid_eval_1d_global = GridEvaluation1DWithGlobal()
initial_time = time.process_time()
grid_eval_1d_global.grid_evaluate()
final_time = time.process_time()
print(f"1d grid, with grid as global variable: {final_time - initial_time} seconds")
这是我得到的输出:
2d grid, with grid as class attribute: 0.8012442529999999 seconds
2d grid, with grid as global variable: 0.20206781899999982 seconds
1d grid, with grid as class attribute: 2.0631387639999996 seconds
1d grid, with grid as global variable: 2.136266148 seconds
如何解释这种性能差异?
我将网格从类属性移至全局变量。我预计这一变化对性能来说是中性的。然而,性能发生了重大变化。
您对网格数据类型的设置不一致。 比较
self.x_2d_values = np.linspace(x_min, x_max, grid_2d_size, dtype=np.float128)
self.y_2d_values = np.linspace(y_min, y_max, grid_2d_size, dtype=np.float128)
与:
x_2d_values = np.linspace(x_min, x_max, grid_2d_size)
y_2d_values = np.linspace(y_min, y_max, grid_2d_size)
未指定时,默认类型为
np.float32
,它比 np.float128
短 4 倍,通常快 4 倍,与您测量的时间相匹配。