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

news2024/11/20 19:29:29

在本文中,我将介绍一些简单的方法,可以将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 web开发,Python爬虫,Python数据分析,人工智能、自动化办公等学习教程。带你从零基础系统性的学好Python!

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

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

在这里插入图片描述
👉Python学习视频600合集👈

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

在这里插入图片描述

温馨提示:篇幅有限,已打包文件夹,获取方式在:文末

👉Python70个实战练手案例&源码👈

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

在这里插入图片描述

👉Python大厂面试资料👈

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

在这里插入图片描述

在这里插入图片描述

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

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

在这里插入图片描述

👉 这份完整版的Python全套学习资料已经上传,朋友们如果需要可以V扫描下方二维码联系领取
保证100%免费

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

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

相关文章

redis的设计与实现(五)——独立功能

1. Redis的其他功能 redis 除了简单对对象的增删改查的功能之外&#xff0c;其实还有其他高级功能&#xff0c;了解这些内容有利于我们更灵活的使用 redis 完成我们的业务功能。 2. 发布与订阅 2.1. 基本概念 很多中间件都有发布与订阅功能&#xff0c;但是&#xff0c;作为一…

拯救鲨鱼!Helping wireshark!wireshark未响应解决方法

前言 做题的的时候 在用wireshark解密tls秘钥的时候 我的小鲨鱼突然未响应了 然后我多次尝试无果 并且殃及池鱼 我电脑上所有的流量包都打不开了&#xff1f;&#xff01;&#xff01;&#xff01; 于是乎 尝试删了重下 还是未响应 开始怀疑电脑 重启电脑两次 还是打…

浏览器原理---事件循环

浏览器原理 学习浏览器原理对于我们开发是很有必要的 我们可以了解到浏览器内部工作原理对自己的代码进行优化 进程线程 首先了解进程和线程 进程就就是内存在正在进行的应用程序 在内存中独占一个内存空间 并且进程之间是隔离的 可以看到每个应用都有一个进程 占用空间内存…

Java | Leetcode Java题解之第25题K个一组翻转链表

题目&#xff1a; 题解&#xff1a; class Solution {public ListNode reverseKGroup(ListNode head, int k) {ListNode hair new ListNode(0);hair.next head;ListNode pre hair;while (head ! null) {ListNode tail pre;// 查看剩余部分长度是否大于等于 kfor (int i 0…

【题目】【信息安全管理与评估】2022年国赛高职组“信息安全管理与评估”赛项样题4

【题目】【信息安全管理与评估】2022年国赛高职组“信息安全管理与评估”赛项样题4 信息安全管理与评估 网络系统管理 网络搭建与应用 云计算 软件测试 移动应用开发 任务书&#xff0c;赛题&#xff0c;解析等资料&#xff0c;知识点培训服务 添加博主wx&#xff1a;liuliu548…

【4月14日】云服务器选购建议 搭建网站、大学生毕设、博客 阿里云 腾讯云 京东云价格对比图

更新日期&#xff1a;4月14日&#xff08;腾讯云小幅涨价&#xff0c;阿里云继续保持1.5折&#xff0c;京东云采购季持续进行&#xff09; 本文纯原创&#xff0c;侵权必究 《最新对比表》已更新在文章头部—腾讯云文档&#xff0c;文章具有时效性&#xff0c;请以腾讯文档为…

多模态对齐方案

最全 LMM 模型结构&#xff08;13种&#xff09;综述本文中我们介绍了 13 中常见的大型多模态模型&#xff08;Large Multimodal Models, LMM&#xff09;&#xff0c;包括 BLIP-2&#xff0c;LLaVA、MiniGPT、Qwen-VL 以及 Ferret 等。https://mp.weixin.qq.com/s/EnK7F0yPYmX…

【浅学】大模型(科普向_持续更新中)

1. 大模型概述 大模型是指具有数千万甚至数亿参数的深度学习模型。 当我们提及大模型时&#xff0c;通常指的是大语言模型&#xff08;Large Language Model&#xff0c;简称LLM&#xff09;&#xff0c;即文字问答模型&#xff0c;其典型代表便是OpenAI的GPT系列。然而&…

LLM--RAG中的文本切分策略及长上下文窗口是否会取代RAG?

1. 文本切割 在使用基于检索的生成模型&#xff08;RAG&#xff09;处理长文本数据时&#xff0c;合理的文本切割策略是提高模型性能和效率的关键。 1.1.文本切割策略核心参数 文本切割策略主要依赖于两个参数&#xff1a;chunksize&#xff08;块大小&#xff09;和overlap…

《由浅入深学习SAP财务》:第2章 总账模块 - 2.6 定期处理 - 2.6.6 年初操作:科目余额结转

2.6.6 年初操作&#xff1a;科目余额结转 在使用事务代码 FAGLB03 查询科目余额时&#xff0c;可以看到按期间的发生额清单。其中&#xff0c;第一行称为“余额结转”&#xff0c;该行的累计余额代表上年度遗留下来的余额&#xff0c;也就是年初余额。对于资产负债表科目而言&a…

可视化大屏C位图:​地理信息—地球焦点图

Hello&#xff0c;我是大千UI工场&#xff0c;本期可视化大屏的焦点图&#xff08;C位&#xff09;分享将地球作为焦点图的情形&#xff0c;欢迎友友们关注、评论&#xff0c;如果有订单可私信。 将地球作为可视化大屏焦点图可以有以下几个作用&#xff1a; 全球数据展示&…

64B/66B GT Transceiver 配置

一、前言 前一篇文章已经讲述了64B/66B的编码原理&#xff0c;此篇文章来配置一下7系列GT的64B/66B编码。并讲述所对应的例子工程的架构&#xff0c;以及部分代码的含义。 二、IP核配置 1、打开7 Series FPGAs Transceiver Wizards&#xff0c;选择将共享逻辑放置在example …

7.Hexo主题安装和自定义

一个Hexo主题&#xff0c;基本上只是一组HTML、CSS和JavaScript文件来定义布局的外观和感觉 在默认情况下&#xff0c;Hexo会附带一个主题&#xff0c;landscape主题 这个主题就比较可靠&#xff0c;确实有效 如果想要使用不同的主题&#xff0c;可以下载并安装一个主题&…

OpenHarmony开源三方库的cmake在IDE上直接引用的问题

前言 DevEco Studio的native工程的C/C部分当前只支持cmake脚本的编译&#xff0c;工程的目录结构如下图所示 在工程中引用第三方库有如下三种方式&#xff0c; 一、find_package模式 通过find_package&#xff0c;可以在指定目录下去搜索已安装的库&#xff08;三方库构建完后…

从零实现诗词GPT大模型:专栏内容规划

一、前情介绍 本系列文章将从头编写一个类GPT的深度学习模型&#xff0c;并在诗词数据集上进行训练&#xff0c;从而可以进行诗词创作。 本次实现的类GPT模型&#xff0c;可以在kaggle上使用免费GPU进行训练&#xff0c;并可以在自己的电脑上进行推理&#xff0c;整个学习过程…

申请OV SSL证书

OV证书&#xff0c;即Organization Validation证书&#xff0c;是一种SSL/TLS证书类型&#xff0c;主要用于企业级应用&#xff0c;例如教育、政府、互联网等行业的大型企业和政府机关部门。与基础的域名验证&#xff08;DV&#xff09;证书相比&#xff0c;OV证书的验证过程更…

入门:多层感知器Multiple-Layer Perceiver, MLP

本文将简单介绍多层感知器&#xff08;MLP&#xff09;的基本概念、原理和应用。MLP是一种前馈人工神经网络&#xff0c;由多层节点组成&#xff0c;每层节点通过权重和偏置与下一层节点相连。MLP在许多领域都有广泛的应用&#xff0c;如分类、回归、自然语言处理等。 本文将分…

Android Studio引入framework.jar包

一. 前言 Android Studio 引入framework.jar 步骤&#xff0c;记录笔记 Android源码编译产生的framework.jar 在不同的版本上生成路径是不同的 Android N/O: 7 和 8 out/target/common/obj/JAVA_LIBRARIES/framework_intermediates/classes.jar Android P/Q: 9 和 10 out/s…

格式化D盘后C盘内的文件会受影响吗?深度解析

在计算机的日常使用中&#xff0c;磁盘格式化是一个常见的操作&#xff0c;它能帮助我们清除磁盘上的数据&#xff0c;为新的数据腾出空间。然而&#xff0c;当涉及到系统盘和其他存储盘时&#xff0c;许多用户会担心一个问题&#xff1a;如果我格式化了非系统盘&#xff0c;比…

SRIO学习(3)使用SRIO IP核进行设计

文章目录 前言一、设计框图二、模块介绍三、上板验证总结 前言 本文将通过使用SRIO IP核实现数据通信&#xff0c;重点在于打通数据链路&#xff0c;具体的协议内容设计并非重点&#xff0c;打通了链路大家自己根据设计需求来即可。 一、设计框图 看了前面高速接口的一些设计…