Python性能优化实录

【向量化计算】将数组逐个相加改为 numpy 数组相加
@simple_mark_time
def func1(aa):
    bb = [0] * aa.shape[1]
    for i in range(aa.shape[0]):
        row = aa[i]
        bb = [row[i] + bb[i] for i in range(len(row))]
    return bb


@simple_mark_time
def func2(aa):
    bb = np.full((aa.shape[1],), 0, dtype=np.float64)
    for i in range(aa.shape[0]):
        row = aa[i]
        bb += row
    return bb


if __name__ == "__main__":
    a = np.random.random((531, 17280))
    b1 = func1(a)  # func1 use time = 2.3398
    b2 = func2(a)  # func2 use time = 0.008
    print(np.all(np.array(b1) == b2))  # True
【一次性申请内存】先初始化 Numpy 数组再往 Numpy 数组中填值,而不是先构造 Numpy 数组的列表再转为 Numpy 数组
@simple_mark_time
def func1(aa):
    bb = np.full((500, 17280), np.nan, dtype=np.float64)
    for i in range(aa.shape[0]):
        row = aa[i]
        bb[i] = row
    return bb


@simple_mark_time
def func2(aa):
    bb = []
    for i in range(500):
        if i < aa.shape[0]:
            row = aa[i]
        else:
            row = np.full((17280,), np.nan, dtype=np.float64)
        bb.append(row)
    bb = np.array(bb)
    return bb


if __name__ == "__main__":
    a1 = np.random.random((50, 17280))
    b1 = func1(a1)  # func1 use time = 0.015
    b2 = func2(a1)  # func2 use time = 0.0489
    print(np.all(b1[~np.isnan(b1)] == b2[~np.isnan(b2)]))  # True
    a2 = np.random.random((500, 17280))
    b1 = func1(a2)  # func1 use time = 0.03
    b2 = func2(a2)  # func2 use time = 0.0369
    print(np.all(b1[~np.isnan(b1)] == b2[~np.isnan(b2)]))  # True
【逻辑简化】之前的逻辑在第一个模块中构造了 numpy 矩阵,在第二个模块中根据要求调整了 numpy 中行的顺序,重新构造了矩阵。现在在第一个模块构造 numpy 矩阵前,就直接根据要求调整了行的顺序,从而不需要再调整顺序及重新构造矩阵。
【异步处理】在任务构造进程中,增加线程间共享的缓存队列,令线程 1 将读取任务并写入缓存队列,线程 2 直接将缓存队列的任务写入进程间共享的计算任务队列;从而必须要再等待全部任务读取完成后才将任务添加到计算任务队列。
【向量化计算】将统计 numpy 矩阵的求和操作从 Python 的原生 sum 函数改为 np.sum 函数
【向量化计算】使用 numpy 的函数实现数组首尾 0 的数量统计

验证实例:【Python性能优化实例】计算 numpy 数组首尾为 0 的数量

【时间复杂度】使用 set 的查找方法,而不是 list 的查找方法

验证实例:【Python性能优化】元素极少时list和set的查找速度


  • 【逻辑简化】如果需要遍历存在于集合 A 而不存在于集合 B 的,那么遍历差集(A - B)的性能将由于遍历并集(A | B)后,再判断是否只在集合 A 中存在
  • 【空间换时间】根据迭代器初始化集合需要消耗 O(N) 的性能,因此如果集合需要多次使用,则不妨先将集合存储下来
  • 【语法优化】如果需要遍历字典的键及对应的值,那么使用 .items() 将获得更好的性能
  • 【逻辑简化】如果需要判断一个值是否在字典的键中,直接判断即可,不需要将字典的键转为集合再判断
  • 【逻辑简化】如果已经确定键存在于字典中,则没有必要使用 get 方法
  • 【逻辑简化】如果我们频繁地获取某个路径较深的元素,不妨直将将其拿出来,以降低每次从路径中获取消耗的性能
  • 【减少 web 请求】在请求 ES 索引时,如果只需要档案中的部分字段,则需要添加 _source 进行请求

你可能感兴趣的:(Python,Python性能优化,python,性能,性能优化)