加速Python循环的12种方法,最高可以提速900倍

在本文中,我将介绍一些简单的方法,可以将Python for循环的速度提高1.3到900倍。

Python内建的一个常用功能是timeit模块。下面几节中我们将使用它来度量循环的当前性能和改进后的性能。

对于每种方法,我们通过运行测试来建立基线,该测试包括在10次测试运行中运行被测函数100K次(循环),然后计算每个循环的平均时间(以纳秒为单位,ns)。

几个简单方法

1、列表推导式

 `# Baseline version (Inefficient way)    # Calculating the power of numbers    # Without using List Comprehension    def test_01_v0(numbers):      output = []      for n in numbers:          output.append(n ** 2.5)      return output        # Improved version    # (Using List Comprehension)    def test_01_v1(numbers):      output = [n ** 2.5 for n in numbers]      return output`

结果如下:

 `# Summary Of Test Results         Baseline: 32.158 ns per loop         Improved: 16.040 ns per loop    % Improvement: 50.1 %         Speedup: 2.00x`

可以看到使用列表推导式可以得到2倍速的提高

2、在外部计算长度

如果需要依靠列表的长度进行迭代,请在for循环之外进行计算。

 `# Baseline version (Inefficient way)    # (Length calculation inside for loop)    def test_02_v0(numbers):      output_list = []      for i in range(len(numbers)):        output_list.append(i * 2)      return output_list        # Improved version    # (Length calculation outside for loop)    def test_02_v1(numbers):      my_list_length = len(numbers)      output_list = []      for i in range(my_list_length):        output_list.append(i * 2)      return output_list`

通过将列表长度计算移出for循环,加速1.6倍,这个方法可能很少有人知道吧。

 `# Summary Of Test Results         Baseline: 112.135 ns per loop         Improved: 68.304 ns per loop    % Improvement: 39.1 %         Speedup: 1.64x`

3、使用Set

在使用for循环进行比较的情况下使用set。

 `# Use for loops for nested lookups    def test_03_v0(list_1, list_2):      # Baseline version (Inefficient way)      # (nested lookups using for loop)      common_items = []      for item in list_1:          if item in list_2:              common_items.append(item)      return common_items        def test_03_v1(list_1, list_2):      # Improved version      # (sets to replace nested lookups)      s_1 = set(list_1)      s_2 = set(list_2)      output_list = []      common_items = s_1.intersection(s_2)      return common_items`

在使用嵌套for循环进行比较的情况下,使用set加速498x

 `# Summary Of Test Results         Baseline: 9047.078 ns per loop         Improved:   18.161 ns per loop    % Improvement: 99.8 %         Speedup: 498.17x`

4、跳过不相关的迭代

避免冗余计算,即跳过不相关的迭代。

 `# Example of inefficient code used to find    # the first even square in a list of numbers    def function_do_something(numbers):      for n in numbers:        square = n * n        if square % 2 == 0:            return square          return None  # No even square found        # Example of improved code that    # finds result without redundant computations    def function_do_something_v1(numbers):      even_numbers = [i for n in numbers if n%2==0]      for n in even_numbers:        square = n * n        return square          return None  # No even square found`

这个方法要在设计for循环内容的时候进行代码设计,具体能提升多少可能根据实际情况不同:

 `# Summary Of Test Results         Baseline: 16.912 ns per loop         Improved: 8.697 ns per loop    % Improvement: 48.6 %         Speedup: 1.94x`

5、代码合并

在某些情况下,直接将简单函数的代码合并到循环中可以提高代码的紧凑性和执行速度。

 `# Example of inefficient code    # Loop that calls the is_prime function n times.    def is_prime(n):      if n <= 1:        return False      for i in range(2, int(n**0.5) + 1):        if n % i == 0:          return False          return True        def test_05_v0(n):      # Baseline version (Inefficient way)      # (calls the is_prime function n times)      count = 0      for i in range(2, n + 1):        if is_prime(i):          count += 1      return count        def test_05_v1(n):      # Improved version      # (inlines the logic of the is_prime function)      count = 0      for i in range(2, n + 1):        if i <= 1:          continue        for j in range(2, int(i**0.5) + 1):          if i % j == 0:            break        else:          count += 1      return count`

这样也可以提高1.3倍

 `# Summary Of Test Results         Baseline: 1271.188 ns per loop         Improved: 939.603 ns per loop    % Improvement: 26.1 %         Speedup: 1.35x`

这是为什么呢?

调用函数涉及开销,例如在堆栈上推入和弹出变量、函数查找和参数传递。当一个简单的函数在循环中被重复调用时,函数调用的开销会增加并影响性能。所以将函数的代码直接内联到循环中可以消除这种开销,从而可能显著提高速度。

⚠️但是这里需要注意,平衡代码可读性和函数调用的频率是一个要考虑的问题。

一些小技巧

6 .避免重复

考虑避免重复计算,其中一些计算可能是多余的,并且会减慢代码的速度。相反,在适用的情况下考虑预计算。

 `def test_07_v0(n):      # Example of inefficient code      # Repetitive calculation within nested loop      result = 0      for i in range(n):        for j in range(n):          result += i * j      return result        def test_07_v1(n):      # Example of improved code      # Utilize precomputed values to help speedup      pv = [[i * j for j in range(n)] for i in range(n)]      result = 0      for i in range(n):        result += sum(pv[i][:i+1])      return result`

结果如下

 `# Summary Of Test Results         Baseline: 139.146 ns per loop         Improved: 92.325 ns per loop    % Improvement: 33.6 %         Speedup: 1.51x`

7、使用Generators

生成器支持延迟求值,也就是说,只有当你向它请求下一个值时,里面的表达式才会被求值,动态处理数据有助于减少内存使用并提高性能。尤其是大型数据集中

 `def test_08_v0(n):      # Baseline version (Inefficient way)      # (Inefficiently calculates the nth Fibonacci      # number using a list)      if n <= 1:        return n      f_list = [0, 1]      for i in range(2, n + 1):        f_list.append(f_list[i - 1] + f_list[i - 2])      return f_list[n]        def test_08_v1(n):      # Improved version      # (Efficiently calculates the nth Fibonacci      # number using a generator)      a, b = 0, 1      for _ in range(n):        yield a        a, b = b, a + b`

可以看到提升很明显:

 `# Summary Of Test Results         Baseline: 0.083 ns per loop         Improved: 0.004 ns per loop    % Improvement: 95.5 %         Speedup: 22.06x`

8、map()函数

使用Python内置的map()函数。它允许在不使用显式for循环的情况下处理和转换可迭代对象中的所有项。

 `def some_function_X(x):      # This would normally be a function containing application logic      # which required it to be made into a separate function      # (for the purpose of this test, just calculate and return the square)      return x**2        def test_09_v0(numbers):      # Baseline version (Inefficient way)      output = []      for i in numbers:        output.append(some_function_X(i))          return output        def test_09_v1(numbers):      # Improved version      # (Using Python's built-in map() function)      output = map(some_function_X, numbers)      return output`

使用Python内置的map()函数代替显式的for循环加速了970x。

 `# Summary Of Test Results         Baseline: 4.402 ns per loop         Improved: 0.005 ns per loop    % Improvement: 99.9 %         Speedup: 970.69x`

这是为什么呢?

map()函数是用C语言编写的,并且经过了高度优化,因此它的内部隐含循环比常规的Python for循环要高效得多。因此速度加快了,或者可以说Python还是太慢,哈。

9、使用Memoization

记忆优化算法的思想是缓存(或“记忆”)昂贵的函数调用的结果,并在出现相同的输入时返回它们。它可以减少冗余计算,加快程序速度。

首先是低效的版本。

 `# Example of inefficient code    def fibonacci(n):      if n == 0:        return 0      elif n == 1:        return 1      return fibonacci(n - 1) + fibonacci(n-2)        def test_10_v0(list_of_numbers):      output = []      for i in numbers:        output.append(fibonacci(i))          return output`

然后我们使用Python的内置functools的lru_cache函数。

 `# Example of efficient code    # Using Python's functools' lru_cache function    import functools        @functools.lru_cache()    def fibonacci_v2(n):      if n == 0:        return 0      elif n == 1:        return 1      return fibonacci_v2(n - 1) + fibonacci_v2(n-2)        def _test_10_v1(numbers):      output = []      for i in numbers:        output.append(fibonacci_v2(i))          return output`

结果如下:

 `# Summary Of Test Results         Baseline: 63.664 ns per loop         Improved: 1.104 ns per loop    % Improvement: 98.3 %         Speedup: 57.69x`

使用Python的内置functools的lru_cache函数使用Memoization加速57x。

lru_cache函数是如何实现的?

“LRU”是“Least Recently Used”的缩写。lru_cache是一个装饰器,可以应用于函数以启用memoization。它将最近函数调用的结果存储在缓存中,当再次出现相同的输入时,可以提供缓存的结果,从而节省了计算时间。lru_cache函数,当作为装饰器应用时,允许一个可选的maxsize参数,maxsize参数决定了缓存的最大大小(即,它为多少个不同的输入值存储结果)。如果maxsize参数设置为None,则禁用LRU特性,缓存可以不受约束地增长,这会消耗很多的内存。这是最简单的空间换时间的优化方法。

10、向量化

 `import numpy as np        def test_11_v0(n):      # Baseline version      # (Inefficient way of summing numbers in a range)      output = 0      for i in range(0, n):        output = output + i          return output        def test_11_v1(n):      # Improved version      # (# Efficient way of summing numbers in a range)      output = np.sum(np.arange(n))      return output`

向量化一般用于机器学习的数据处理库numpy和pandas

 `# Summary Of Test Results         Baseline: 32.936 ns per loop         Improved: 1.171 ns per loop    % Improvement: 96.4 %         Speedup: 28.13x`

11、避免创建中间列表

使用filterfalse可以避免创建中间列表。它有助于使用更少的内存。

 `def test_12_v0(numbers):      # Baseline version (Inefficient way)      filtered_data = []      for i in numbers:        filtered_data.extend(list(            filter(lambda x: x % 5 == 0,                    range(1, i**2))))            return filtered_data`

使用Python的内置itertools的filterfalse函数实现相同功能的改进版本。

 `from itertools import filterfalse        def test_12_v1(numbers):      # Improved version      # (using filterfalse)      filtered_data = []      for i in numbers:        filtered_data.extend(list(            filterfalse(lambda x: x % 5 != 0,                        range(1, i**2))))                return filtered_data`

这个方法根据用例的不同,执行速度可能没有显著提高,但通过避免创建中间列表可以降低内存使用。我们这里获得了131倍的提高

 `# Summary Of Test Results         Baseline: 333167.790 ns per loop         Improved: 2541.850 ns per loop    % Improvement: 99.2 %         Speedup: 131.07x`

12、高效连接字符串

任何使用+操作符的字符串连接操作都会很慢,并且会消耗更多内存。使用join代替。

 `def test_13_v0(l_strings):      # Baseline version (Inefficient way)      # (concatenation using the += operator)      output = ""      for a_str in l_strings:        output += a_str          return output        def test_13_v1(numbers):      # Improved version      # (using join)      output_list = []      for a_str in l_strings:        output_list.append(a_str)          return "".join(output_list)`

该测试需要一种简单的方法来生成一个较大的字符串列表,所以写了一个简单的辅助函数来生成运行测试所需的字符串列表。

 `from faker import Faker        def generate_fake_names(count : int=10000):      # Helper function used to generate a      # large-ish list of names      fake = Faker()      output_list = []      for _ in range(count):        output_list.append(fake.name())          return output_list        l_strings = generate_fake_names(count=50000)`

结果如下:

 `# Summary Of Test Results         Baseline: 32.423 ns per loop         Improved: 21.051 ns per loop    % Improvement: 35.1 %         Speedup: 1.54x`

使用连接函数而不是使用+运算符加速1.5倍。为什么连接函数更快?

使用+操作符的字符串连接操作的时间复杂度为O(n²),而使用join函数的字符串连接操作的时间复杂度为O(n)。

总结

本文介绍了一些简单的方法,将Python for循环的提升了1.3到970x。

  • 使用Python内置的map()函数代替显式的for循环加速970x

  • 使用set代替嵌套的for循环加速498x[技巧#3]

  • 使用itertools的filterfalse函数加速131x

  • 使用lru_cache函数使用Memoization加速57x

关于Python学习指南

学好 Python 不论是就业还是做副业赚钱都不错,但要学会 Python 还是要有一个学习规划。最后给大家分享一份全套的 Python 学习资料,给那些想学习 Python 的小伙伴们一点帮助!

包括:Python激活码+安装包、Python web开发,Python爬虫,Python数据分析,人工智能、自动化办公等学习教程。让你从零基础系统性的学好Python!

👉Python所有方向的学习路线👈

Python所有方向路线就是把Python常用的技术点做整理,形成各个领域的知识点汇总,它的用处就在于,你可以按照上面的知识点去找对应的学习资源,保证自己学得较为全面。(全套教程文末领取)

在这里插入图片描述

👉Python学习视频600合集👈

观看零基础学习视频,看视频学习是最快捷也是最有效果的方式,跟着视频中老师的思路,从基础到深入,还是很容易入门的。

在这里插入图片描述

温馨提示:篇幅有限,已打包文件夹,获取方式在:文末
👉Python70个实战练手案例&源码👈

光学理论是没用的,要学会跟着一起敲,要动手实操,才能将自己的所学运用到实际当中去,这时候可以搞点实战案例来学习。

在这里插入图片描述

👉Python大厂面试资料👈

我们学习Python必然是为了找到高薪的工作,下面这些面试题是来自阿里、腾讯、字节等一线互联网大厂最新的面试资料,并且有阿里大佬给出了权威的解答,刷完这一套面试资料相信大家都能找到满意的工作。

在这里插入图片描述

在这里插入图片描述

👉Python副业兼职路线&方法👈

学好 Python 不论是就业还是做副业赚钱都不错,但要学会兼职接单还是要有一个学习规划。

在这里插入图片描述

👉 这份完整版的Python全套学习资料已经上传,朋友们如果需要可以扫描下方CSDN官方认证二维码或者点击链接免费领取保证100%免费

点击免费领取《CSDN大礼包》:Python入门到进阶资料 & 实战源码 & 兼职接单方法 安全链接免费领取

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

如何监控容器或K8s中的OpenSearch

概述 当前 OpenSearch 使用的越来越多, 但是 OpenSearch 生态还不尽完善. 针对如下情况: 监控容器化或运行在 K8s 中的 OpenSearch 我查了下, 官方还没有提供完备的方案. 这里如何监控 K8s 中的 OpenSearch, 包括安装 exporter 插件、采集、展示全环节。 OpenSearch 简介…

RTL设计指导原则

RTL设计指导原则 一、面积与速度互换原则 1. 电路设计中的面积与速度 面积&#xff1a;设计所消耗的目标器件的硬件资源数量或者ASIC芯片的面积。 FPGA&#xff1a;所消耗的触发器(FF&#xff09;和查找表&#xff08;LUT)数量来衡量; ASIC&#xff1a;设计的面积、门数等衡…

【免安装的MATLAB--MATLAB online】

目录&#xff1a; 前言账号的注册图片处理的示例准备图片脚本函数 总结 前言 在计算机、数学等相关专业中&#xff0c;或多或少都会与MATLAB产生藕断丝连的联系&#xff0c;如果你需要使用MATLAB&#xff0c;但是又不想要安装到自己的电脑上&#xff08;它实在是太大了啊&#…

华为海思数字芯片设计笔试第四套

声明 下面的题目作答都是自己认为正确的答案&#xff0c;并非官方答案&#xff0c;如果有不同的意见&#xff0c;可以评论区交流。 这些题目也是笔者从各个地方收集的&#xff0c;感觉有些题目答案并不正确&#xff0c;所以在个别题目会给出自己的见解&#xff0c;欢迎大家讨论…

L1-041 寻找250

对方不想和你说话&#xff0c;并向你扔了一串数…… 而你必须从这一串数字中找到“250”这个高大上的感人数字。 输入格式&#xff1a; 输入在一行中给出不知道多少个绝对值不超过1000的整数&#xff0c;其中保证至少存在一个“250”。 输出格式&#xff1a; 在一行中输出第一次…

【架构-8】Lambda和Kappa架构

Lambda架构&#xff1f; Lambda架构&#xff08;三层架构&#xff09;&#xff1a; &#xff08;1&#xff09;将数据处理分为实时和离线两部分。离线部分通过批量计算处理数据&#xff0c;实时部分则通过增加追加方式将数据合并到批处理中。 &#xff08;2&#xff09;批处理…

js canvas实现裁剪图片并下载

简历上给自己挖的坑&#xff0c;面试被拷打&#xff0c;早就该填了T.T 参考&#xff1a;【js canvas实现图片裁剪】 https://www.bilibili.com/video/BV1QK411d7n1/?share_sourcecopy_web&vd_sourcebf743b20b76eab11028ba2fb05f056b4 效果 思路 组成&#xff1a; 上传文…

基于Springcloud可视化项目:智慧工地可视化大数据云平台源码

目录 技术架构 智慧工地系统在实际推行过程中遇到的问题 智慧工地接纳程度较低 基础设施条件有待完善 智慧工地整体生态尚未完善 智慧工地平台各功能模块 施工过程工信程息信管息理管模理块 人员管理模块 生产管理模块 技术管理模块 质量管理模块 安全管理模块 绿…

记录一个Kafka客户端Offset Explore连不上的问题

我昨天把集群重装了一下&#xff0c;再连这个工具就连不上了&#xff08;你先把zk和kafka在集群启起来&#xff09;&#xff0c;报错截图如下&#xff1a; 英文翻译过来大概就是说遍历zk指定路径不存在&#xff0c;我还以为zk的问题&#xff0c;回去又把zk的文档翻了一遍&#…

多线程代码案例之阻塞队列

目录 1.生产者消费者模型 2.使用标准库中的阻塞队列 3.模拟实现阻塞队列 在介绍阻塞队列之前&#xff0c;会先介绍一些前置知识&#xff0c;像队列&#xff1a;有普通队列、优先级队列、阻塞队列、和消息队列。前面两个是线程不安全的&#xff0c;而后面两个是线程安全的。本…

FFmpeg: 自实现ijkplayer播放器--03UI界面设计

文章目录 UI设计流程图UI设计界面点击播放功能实现 UI设计流程图 UI设计界面 主界面 控制条 播放列表 画面显示 标题栏 设置界面 提示框 点击播放功能实现 槽函数实现&#xff1a; connect(ui->ctrlBarWind, &CtrlBar::SigPlayOrPause, this, &Main…

软件杯 深度学习卷积神经网络垃圾分类系统 - 深度学习 神经网络 图像识别 垃圾分类 算法 小程序

文章目录 0 简介1 背景意义2 数据集3 数据探索4 数据增广(数据集补充)5 垃圾图像分类5.1 迁移学习5.1.1 什么是迁移学习&#xff1f;5.1.2 为什么要迁移学习&#xff1f; 5.2 模型选择5.3 训练环境5.3.1 硬件配置5.3.2 软件配置 5.4 训练过程5.5 模型分类效果(PC端) 6 构建垃圾…

InnoDB中高度为3的B+树最多可以存多少数据?

参考&#xff1a; &#x1f525;我说MySQL每张表最好不超过2000万数据&#xff0c;面试官让我回去等通知&#xff1f; - 掘金 考虑到磁盘IO是非常高昂的操作&#xff0c;计算机操作系统做了预读的优化&#xff0c;当一次IO时&#xff0c;不光把当前磁盘地址的数据&#xff0c;…

QtCreater 使用

QtCreater 创建项目 1.刚进入 QtCreater 的界面是这样的一个界面 ① 创建一个新的文件&#xff0c;那么我们就选择左上角的 “文件” ② 点击新建文件&#xff0c;或者也可以直接使用快捷键 CtrlN 此时就会弹出对话框&#xff0c;让我们选择想要创建的文件&#xff1a; Appli…

stm32f103---按键控制LED---代码学习

目录 一、总体代码 二、LED端口初始化分析 ​编辑 三、LED灭的控制 四、LED亮 五、按键初始化 ​ 六、按键控制LED的功能 一、总体代码 这里使用到了LED灯和按键&#xff0c;实现效果是当按键按下时灯的亮灭转化 #include "stm32f10x.h" #include "bsp_led…

Notion2024年最新桌面端安装+汉化教程,支持MAC和WIN版本

Notion 是一个多功能的协作工具&#xff0c;可以用于个人和团队的知识管理、项目管理、笔记记录和协同编辑等。它提供了灵活的页面和数据库功能&#xff0c;可以根据不同需求进行自定义和组织。Notion 能够帮助用户更高效地组织和共享信息&#xff0c;提升工作效率和团队合作。…

ThingsBoard通过服务端获取客户端属性或者共享属性

MQTT基础 客户端 MQTT连接 通过服务端获取属性值 案例 1、首先需要创建整个设备的信息&#xff0c;并复制访问令牌 ​2、通过工具MQTTX连接上对应的Topic 3、测试链接是否成功 4、通过服务端获取属性值 5、在客户端查看对应的客户端属性或者共享属性的key 6、查看整个…

改进YOLOv8系列:结合自研注意力模块MultiScaleAttentiveConv (MSAConv)

改进YOLOv8注意力系列七:结合空间关系增强注意力SGE、SKAttention动态尺度注意力、全局上下文信息注意力Triplet Attention 代码MultiScaleAttentiveConv (MSAConv)本文提供了改进 YOLOv8注意力系列包含不同的注意力机制以及多种加入方式,在本文中具有完整的代码和包含多种更…

蓝桥杯嵌入式(G431)备赛笔记——DMA+ADC(单通道+多通道)

单通道&#xff1a; 开启循环模式&#xff0c;两个参数设为word u32 adc_tick0; u32 r37_value0; u32 r38_value0; float r37_volt0; float r38_volt0;//DMAADCvoid DMA_ADC() {if(uwTick-adc_tick<100) return;adc_tick uwTick;HAL_ADC_Start_DMA(&hadc2, &r37_v…

vivado ila 运行触发器、停止触发器、使用自动重新触发

运行触发器 您可在 2 种不同模式下运行或装备 ILA 核触发器 &#xff1a; • “ Run Trigger ” &#xff1a; 选择要装备的 ILA 核 &#xff0c; 然后单击“ ILA 仪表板 (ILA Dashboard) ”窗口或“硬件 (Hardware) ”窗口 工具栏上的“ Run Trigger ”按钮即可装备 IL…