python中一些代码提速技巧

news2024/9/25 15:30:33

目录

  • 用set而非list进行查找
  • 用dict而非两个list进行匹配查找
  • 优先使用for循环而不是while循环
  • 循环代替递归
  • 用缓存机制加速递归函数
  • 用numba加速Python函数
  • 使用collections.Counter加速计数
  • 使用collections.ChainMap加速字典合并
  • 使用map代替推导式进行加速
  • 使用filter代替推导式进行加速
  • 多线程加速IO密集型任务
  • 应用多进程加速CPU密集型任务

用set而非list进行查找

列表是一个有序的可重复元素的集合,它可以包含任意类型的对象。列表的实现通常使用动态数组,这意味着可以通过索引来快速访问元素。

集合是一个无序的不重复元素的集合,它只能包含可散列的对象(例如,数字、字符串等)。集合的实现通常使用哈希表或类似的数据结构,这使得它能够在O(1)的时间复杂度内查找元素。

由于集合使用哈希表实现,它可以在常数时间内(O(1))执行查找操作,而列表需要在最坏情况下遍历整个列表才能找到目标元素,其时间复杂度为O(n)。

集合是用来存储唯一元素的,所以在查找时,它不需要考虑是否有重复的元素,这也使得它在查找时更加高效。

list_d = [x**2 + 1 for x in range(1000000)]

set_d = (x**2 + 1 for x in range(1000000))

# 慢
1098987 in list_d

# 快
1098987 in set_d

用dict而非两个list进行匹配查找

看如下例子:

list_a = [2*i - 1 for i in range(1000000)]

list_b = [i**2 for i in list_a]

# 列表查找
print(list_b[list_a.index(876567)])

# 使用字典按照key查找
dict_ab = dict(zip(list_a, list_b))
print(dict_ab.get(876567, None))

与set同理,dict也是使用哈希表实现,也可以在常数时间内(O(1))执行查找操作。

优先使用for循环而不是while循环

示例:

import time


def time_cal(func):
    def wrapper():
        t1 = time.time()
        func()
        print(f"耗时:{time.time() - t1}")
    return wrapper


@time_cal
def func1():
    s = 0
    i = 0
    while s < 10000:
        s += 1
        i += 1


@time_cal
def func2():
    s = 0
    for i in range(10000):
        s += 1


if __name__ == "__main__":
    func1()
    func2()

结果如下:

耗时:0.0007779598236083984
耗时:0.00047516822814941406

循环代替递归

示例如下:

import time


def time_cal(func):
    def wrapper(*args, **kwargs):
        t1 = time.time()
        func(*args, **kwargs)
        print(f"耗时:{time.time() - t1}")
    return wrapper


def func1(n):
    # 斐波那契函数
    return (1 if n in (1, 2) else (func1(n-1) + func1(n-2)))


@time_cal
def func2(n):
    if n in (1, 2):
        return 1
    a, b = 1, 1
    for i in range(2, n):
        a, b = b, a + b
    return b


if __name__ == "__main__":
    t1 = time.time()
    func1(30)
    print(f"耗时:{time.time() - t1}")

    func2(30)

结果如下:

耗时:0.1676180362701416
耗时:7.867813110351562e-06

递归虽然简单,但是可能存在以下问题:

  • 在递归中,每次函数调用都会涉及到压栈和弹栈的操作,这会导致额外的开销。每次函数调用都需要保存当前函数的状态(包括局部变量、返回地址等),而循环则避免了这种开销。
  • 另外有最大的函数调用栈深度限制。当递归的深度超过这个限制时,会引发栈溢出错误。
  • 一些编译器可以对尾递归做出优化,将其转换为类似循环的形式,从而避免了递归的开销。
  • 在一些问题中,递归可能会导致重复计算,因为递归往往会反复调用相同的子问题,而迭代可以使用循环变量来避免这种情况。

用缓存机制加速递归函数

上面说到,递归可能会导致重复计算,会反复调用相同的子问题。可以使用缓存减少重复计算。

代码如下:

import time
from functools import lru_cache

@lru_cache(100)
def func1(n):
    # 斐波那契函数
    return (1 if n in (1, 2) else (func1(n-1) + func1(n-2)))


if __name__ == "__main__":
    t1 = time.time()
    func1(30)
    print(f"耗时:{time.time() - t1}")

执行时间如下:

耗时:1.3828277587890625e-05

可以看到时间明显少了几个数量级。

用numba加速Python函数

未加速的代码:

import time


def time_cal(func):
    def wrapper(*args, **kwargs):
        t1 = time.time()
        func(*args, **kwargs)
        print(f"耗时:{time.time() - t1}")
    return wrapper


def my_power(x):
    return x**2


@time_cal
def my_power_sum(n):
    s = 0
    for i in range(1, n+ 1):
        s += my_power(i)
    return s


if __name__ == "__main__":
    my_power_sum(1000000)

执行时间如下:

耗时:0.324674129486084

使用numba如下:

import time
from numba import jit


def time_cal(func):
    def wrapper(*args, **kwargs):
        t1 = time.time()
        func(*args, **kwargs)
        print(f"耗时:{time.time() - t1}")
    return wrapper


@jit
def my_power(x):
    return x**2


@time_cal
@jit
def my_power_sum(n):
    s = 0
    for i in range(1, n+ 1):
        s += my_power(i)
    return s


if __name__ == "__main__":
    my_power_sum(1000000)

执行时间:

耗时:0.25246715545654297

使用collections.Counter加速计数

示例如下:

import time
from collections import Counter


def time_cal(func):
    def wrapper(*args, **kwargs):
        t1 = time.time()
        func(*args, **kwargs)
        print(f"耗时:{time.time() - t1}")
    return wrapper


@time_cal
def func1(data):
    # 普通方法
    values_count = {}
    for i in data:
        i_count = values_count.get(i, 0)
        values_count[i] = i_count + 1
    print(values_count.get(4, 0))


@time_cal
def func2(data):
    # 加速方法
    values_count = Counter(data)
    print(values_count.get(4, 0))


if __name__ == "__main__":
    data = [x**2 % 1989 for x in range(2000000)]
    func1(data)
    func2(data)

运行结果如下:

8044
耗时:0.27747488021850586
8044
耗时:0.14070415496826172

使用collections.ChainMap加速字典合并

示例如下:

import time
from collections import ChainMap


def time_cal(func):
    def wrapper(*args, **kwargs):
        t1 = time.time()
        func(*args, **kwargs)
        print(f"耗时:{time.time() - t1}")
    return wrapper


@time_cal
def func1(dic_a, dic_b, dic_c, dic_d):
    # 普通方法
    res = dic_a.copy()
    res.update(dic_b)
    res.update(dic_c)
    res.update(dic_d)
    print(res.get(9999, 0))


@time_cal
def func2(dic_a, dic_b, dic_c, dic_d):
    # 加速方法
    chain = ChainMap(dic_a, dic_b, dic_c, dic_d)
    print(chain.get(9999, 0))


if __name__ == "__main__":
    dic_a = {i: i + 1 for i in range(1, 1000000, 2)}
    dic_b = {i: 2*i + 1 for i in range(1, 1000000, 3)}
    dic_c = {i: 3*i + 1 for i in range(1, 1000000, 5)}
    dic_d = {i: 4*i + 1 for i in range(1, 1000000, 7)}

    func1(dic_a, dic_b, dic_c, dic_d)
    func2(dic_a, dic_b, dic_c, dic_d)

运行结果如下:

10000
耗时:0.05382490158081055
10000
耗时:4.57763671875e-05

使用map代替推导式进行加速

示例如下:

import time


def time_cal(func):
    def wrapper(*args, **kwargs):
        t1 = time.time()
        func(*args, **kwargs)
        print(f"耗时:{time.time() - t1}")
    return wrapper


@time_cal
def func1():
    # 普通方法
    res = [x**2 for x in range(1, 1000000, 3)]


@time_cal
def func2():
    # 加速方法
    res = map(lambda x: x**2, range(1, 1000000, 3))


if __name__ == "__main__":
    func1()
    func2()

运行结果如下:

耗时:0.0947120189666748
耗时:1.0013580322265625e-05

使用filter代替推导式进行加速

示例如下:

import time


def time_cal(func):
    def wrapper(*args, **kwargs):
        t1 = time.time()
        func(*args, **kwargs)
        print(f"耗时:{time.time() - t1}")
    return wrapper


@time_cal
def func1():
    # 普通方法
    res = [x**2 for x in range(1, 1000000, 3) if x % 7 == 0]


@time_cal
def func2():
    # 加速方法
    res = filter(lambda x: x%7 == 0, range(1, 1000000, 3))


if __name__ == "__main__":
    func1()
    func2()

运行如下:

耗时:0.03171205520629883
耗时:1.0013580322265625e-05

多线程加速IO密集型任务

低速方法
在这里插入图片描述高速方法
在这里插入图片描述

应用多进程加速CPU密集型任务

低速方法
在这里插入图片描述
高速方法
在这里插入图片描述

参考:
https://mp.weixin.qq.com/s/oF35_g4gdPeprHSvw4Mnyg

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1074382.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

nacos2.0.2漏洞分析及解决方法

绕过鉴权情况 1. userAgentAuthWhite 设置为true&#xff0c;官方没有还没有解析为啥可以通过设置userAgent可以绕过鉴权 实验一 只要把请求header&#xff1a;User-Agent设置为&#xff1a;Nacos-Server&#xff0c;即可绕过鉴权 实验二 只要把请求header&#xff1a;User…

SpringBoot原理解析篇(一):parent 版本管理

SpringBoot 是由 Pivotal 团队提供的全新框架&#xff0c;其设计目的是用来 简化 Spring 应用的初始搭建以及开发过程。 Spring 程序缺点&#xff1a;依赖设置繁琐、配置繁琐 SpringBoot 程序优点&#xff1a;起步依赖&#xff08;简化依赖配置&#xff09;、自动配置&#x…

查看当前目录下文件所占用内存 du -sh

1. du -sh 查看当前目录下文件所占用内存 2.查看当前文件夹下&#xff0c;每个文件所占用内存 du -ah --max-depth1/

点云配准流程

迭代最近点算法&#xff08;Iterative CLosest Point简称ICP算法&#xff09; ICP算法对待拼接的2片点云&#xff0c;首先根据一定的准则确立对应点集P与Q&#xff0c;其中对应点对的个数&#xff0c;然后通过最小二乘法迭代计算最优的坐标变换&#xff0c;即旋转矩阵R和平移矢…

Soul CEO张璐团队优化治理平台安全生态,构建健康社交秩序

致力于构建真实、温暖、多元线上社交空间的Soul APP,在2023第二季度发布了全新的《Soul生态安全治理报告》。报告显示,Soul 主要以五大安全点位为阵地,开展专项安全生态治理,五大专项分别是反电信网络诈骗、引导社交礼仪规范、未成年保护、用户共治众裁和防治网暴骚扰。Soul CE…

红动大湾区!“红西凤”领衔西凤酒核心产品亮相秋糖

执笔 | 文 清 编辑 | 萧 萧 600亿元酒水消费规模的广东市场&#xff0c;再遇中国四大名酒之一的西凤酒&#xff0c;会碰撞出什么样的火花&#xff1f; 10月7日-11日&#xff0c;西凤酒携红西凤系列、西凤酒珍藏版、老绿瓶系列等全明星产品阵容&#xff0c;在深圳华侨城洲…

WindowsServer2019-部署与管理Active Directory域服务-01

文章目录 创建和配置域控制器1、创建域控制器步骤1&#xff1a;更名计算机步骤2&#xff1a;修改DC的IP地址步骤3&#xff1a;安装Active Directory域服务和DNS服务器角色步骤4&#xff1a;提升为域控制器 2、添加额外域控制器&#xff08;BDC&#xff09;步骤1&#xff1a;按照…

Vue3目录结构与Yarn.lock 的版本锁定

Vue目录结构与Yarn.lock 的版本锁定 一、Vue3.0目录结构图总览 举个例子看vue的目录&#xff0c;一开始不知道该目录是什么意思目录里各个文件包里安放有什么&#xff0c;程序员在哪里操作该如何操作。 下图目录看Vue新项目 VS Code 打开文件包后出现一列目录 二、目录结构 1…

IMU应用于犬类步态分析

客观的步态分析可以为临床医生提供治疗决策的重要信息。它不仅可以用于诊断&#xff0c;还为育种提供重要信息。而目前在兽医学中用于收集运动学和动力学数据的步态分析系统非常昂贵并且需要专门的空间。 惯性测量单元系统为犬类步态分析提供了新思路。IMU传感器可以成为光学运…

一文拿捏线程和线程池的创建方式

1 创建线程的四种方式 继承 Thread 类并重写 run方法创建线程&#xff0c;实现简单但不可以继承其他类&#xff1b; 实现 Runnable 接口并重写 run 方法&#xff0c;避免了单继承局限性&#xff0c;编程更加灵活&#xff0c;实现解耦&#xff1b; 实现 Callable 接口并重写 c…

国人的骄傲:LLaVA理解图片的妙用

随着多模态大语言和视觉助手LLaVA的突破性发展&#xff0c;对图像&#xff0c;文本甚至模因的理解变得非常容易。这种先进的人工智能技术能够无缝理解和解释各种形式的媒体&#xff0c;弥合语言和视觉理解之间的差距。其令人难以置信的用例包括增强的图像识别、上下文感知文本分…

白银做期货还是做现货?

现货白银和期货白银都是保证金交易品种&#xff0c;都具有一定的资金杠杆&#xff0c;新手投资者在它们之间进行选择的时候&#xff0c;可能会遇到一定的困难&#xff0c;但是只要投资者真正了解过它们的区别&#xff0c;在选择时思路就会更加清晰&#xff0c;能够根据自己的实…

EMI滤波器有哪几种应用和选择?|深圳比创达EMC

EMI滤波器有哪几种应用和选择&#xff1f;相信不少人是有疑问的&#xff0c;今天深圳市比创达电子科技有限公司就跟大家解答一下&#xff01; 一、EMI滤波器的电路形式 1、C型滤波器由三端电容和穿心电容构成&#xff0c;适用于抑制高频。C型滤波器两端均可视为低阻抗&#x…

Ant Vue Table 合并单元格

项目开发中&#xff0c;有时候需要实现单元格合并的需求,这里记录一下在Ant Design Vue的实现。 <template><div><a-table bordered :data-source"dataSource" :columns"columns"></a-table></div> </template> <…

【数据结构与算法】二叉树的以及二叉排序树的实现

目录 通过数组实现二叉树 通过链表实现二叉树 排序二叉树的实现 通过数组实现二叉树 该实现方式只能用于完全二叉树&#xff0c;因为如果是普通二叉数的话&#xff0c;数组中会出现空隙&#xff0c;会导致空间的利用率会降低。 实现思路&#xff1a; 因为假设一个父节点的…

电商数据的采集标准

品牌在做控价或者数据分析时&#xff0c;都离不开对数据的采集&#xff0c;只有准确的进行了数据采集&#xff0c;才能保证控价结果和分析结果的准确性。所以对于电商数据的采集&#xff0c;其标准也相对比较高。 力维网络有专业稳定的电商数据采集系统&#xff0c;可以多平台、…

二维码智慧门牌管理系统:智能化生活的未来

文章目录 前言一、二维码智慧门牌管理系统的特点二、二维码智慧门牌管理系统的应用三、二维码智慧门牌管理系统的前景 前言 随着科技的不断发展&#xff0c;我们的生活变得越来越智能化。近日&#xff0c;一种名为“二维码智慧门牌管理系统”的新型技术引起了人们的广泛关注。…

10月12日19:30|BIM+GIS用于公路施工组织策划专题直播

当前BIMGIS三维数字沙盘技术成为了交通建设领域的一大热门话题。交通部也在近日发布了《推荐公路数字化转型的意见》&#xff0c;明确指出了BIMGIS技术应用对于公路数字化转型的重要性。那么&#xff0c;公路工程建设施工组织策划阶段&#xff0c;该如何更好地应用BIMGIS技术呢…

C语言--文件操作详解(1)文件操作的基本概念及文件操作函数用法举例

前言 链接: 八功能通讯录 这是我们前面写了通讯录的程序&#xff0c;当通讯录运行起来的时候&#xff0c;可以给通讯录中增加、删除数据&#xff0c;此时数据是存放在内存中&#xff0c;当程序退出的时候&#xff0c;通讯录中的数据自然就不存在了&#xff0c;等下次运行通讯录…

国外SCADA软件比较

讨论工业自动化中使用的各种SCADA软件以及它们之间的比较。 您正在从事一个工业自动化项目&#xff0c;您肯定需要SCADA。很多时候&#xff0c;我们对于需要为应用选择什么是正确的SCADA感到困惑。 因为涉及的因素很多&#xff0c;忽略其中任何一个因素都必然会导致性能出现障…