Py学习  »  Python

求你不要再用这几个 Python 编码了,太慢了...

数据STUDIO • 6 月前 • 201 次点击  


Python 脚本的运行速度一直都是开发者诟病的地方,无论是网站运行迟缓,还是数据分析工作长达数小时,代码运行缓慢将影响所有相关人员,使其效率大打折扣,甚至可能危及项目的成功。

在本文中,我将介绍一些的最常见的拖垮性能的一些编程代码,并推荐相应的解决方法,为你的 Python 涡轮增压!当然,如果你不限于此,推荐你看下前面推荐 mojo 语言 比 Python 快几万倍:比Python快9万倍!AI编程语言Mojo正式开源

01 循环

我们通常对for循环情有独钟,在需要进行大量作业时,首先想到的就是使用 for 循环。而在优化速度时,尤其是在讨论大型数据集时,这些循环简直就是噩梦般存在。

数字加法:将一大串数字的平方相加,首先使用一个循环方法:

numbers = [12345, ... , 10000]  # A big list
total = 0
for number in numbers:
    squared = number * number
    total += squared

在引擎下,Python 会对每个元素进行大量的单独计算。

解决方法:NumPy

这时,NumPy 就像超级英雄一样,它的矢量化简直无敌!一次性对整个数组执行操作。

import numpy as np

numbers = np.array([12345, ... , 10000])  
squared = numbers * numbers  # Vectorized squaring!
total = squared.sum()

NumPy 不需要逐个元素计算,而是一气呵成地处理整个计算过程。

折中方案

列表推导式:

total = sum(number * number for number in numbers)

它们通常比传统循环更快,但在进行高强度数值计算时,可能无法与 NumPy 匹敌。

02 错用工具

对于 Python 来说,仅仅依靠列表来完成所有任务无异于只用一只手编程。

查询电话号码:假设有一个这样的联系人列表:

contacts = [
    {"name""Alice""phone""123-4567"},
    {"name""云朵君""phone""789-0123"},
    # ... more contacts
]

查找云朵君的号码意味着要扫描列表,可能要检查每一个联系人。

解决方法:具有超能力的数据结构

  • 字典:快速查找的好帮手

如果要通过关键字(如 "姓名")进行搜索,字典就是你的救星。

contacts_dict = {
    "Alice""123-4567",
    "云朵君" "789-0123",
    # ... more contacts
}
bobs_number = contacts_dict["云朵君"]  # Instant access!
  • 集合: 强制执行唯一性

需要跟踪唯一的网站访问者吗?集合会自动删除重复项。

unique_visitors = set()
unique_visitors.add("192.168.1.100")
unique_visitors.add("124.58.23.5")
unique_visitors.add("192.168.1.100")  # No duplicate added

Python 还提供了更多超级有用的工具:有序字典、特殊队列 deques 等。了解何时使用这些工具标志着优秀与卓越脚本之间的区别。

03 在黑盒中优化

你一定对这种感觉很熟悉,虽然发现了代码运行缓慢,但却对原因一无所知时。这就好比在没有灯光的情况下修灯泡。

假设你有一个计算斐波那契数字的函数。你费尽心力来完善数学推理,但速度仍然很慢。结果发现,瓶颈可能是某些看不见的东西,比如在边运行代码边将结果记录到磁盘文件中。

解决方法:cProfile 来救场!

Python 内置的cProfile模块就是你的性能侦探。下面介绍如何使用它:

import cProfile

def my_function():
    # Your code to be profiled

cProfile.run('my_function()')

这将生成大量统计数据。主要内容如下

  • ncalls: 函数被调用的次数。
  • tottime: 在函数中花费的总时间。
  • cumtime: 与 tottime 类似,但包括调用其中所有函数所花费的时间。

筛选线索这些数字将指出真正的瓶颈,帮助你将优化工作集中在影响最大的地方。

04:重复造轮子

重新造轮子就像决定徒步穿越整个国家,而不是乘坐飞机前往目的地。就像上一步介绍的python工具一样,其实Python 真的有很多神奇的内置函数来帮助你完成你的工作。要不然python怎么会被戏称胶水语言呢。

排序:可以编写自己的冒泡排序实现......或者使用 Python 的sorted():

my_list = [53142]

# The long way (probably pretty slow)
def my_bubble_sort(list): 
   # ... your sorting code here

# The Pythonic way
sorted_list = sorted(my_list)

很有可能,你的自定义排序算法甚至无法达到内置算法的效率。当然,如果你是编程超级高手,不用在意这些🤓

解决方法:借助标准库

Python 标准库简直就你最好最强大的朋友。比如用来解决本次问题的强大的工具有:

  • itertools: 使用迭代器为你的工作增效(想想高级循环的效率)
  • heapq:用于管理堆(优先队列)
  • bisect:以迅雷不及掩耳之势让排序列表保持有序。

学习内置标准库的时间就是节省下来的优化时间。

05:与硬盘交互太多

将电脑内存(RAM)视为超快速工作区,将硬盘视为另一端的存储仓库。每次访问或修改文件,就相当于派遣一名信使来回奔波。往返次数过多,你的代码就会开始感觉到等待时长。就像第三节提到的,边运行代码,边存储文件到磁盘,还有往复读取、写入的更糟糕的过程。

逐行缓慢:假设正在处理一个庞大的日志文件:

with open("huge_log.txt""r"as file:
    for line in file:
        # Process each line slowly
  • 每读取line,就意味着要从硬盘上单独取一次数据。

解决方法:更聪明地工作,而不是更努力地工作

  • 一次读完(如果合适): 对于较小的文件,有时最快的方法是将其全部读入内存:
with open("huge_log.txt""r"as file:
    contents = file.read() 
    # Process contents in memory
  • 缓冲拯救: 当你需要细粒度的控制时,缓冲功能就能拯救你:
with open("huge_log.txt""r"as file:
    while True:
        chunk = file.read(4096)  # Read in chunks
        if not chunk:
            break
        # Process the chunk

以块为单位,而不是以字节为单位思考尽量减少前往 "仓库" 的次数,这将带来巨大的不同。


🏴‍☠️宝藏级🏴‍☠️ 原创公众号『数据STUDIO』内容超级硬核。公众号以Python为核心语言,垂直于数据科学领域,包括可戳👉 PythonMySQL数据分析数据可视化机器学习与数据挖掘爬虫  等,从入门到进阶!

长按👇关注- 数据STUDIO -设为星标,干货速递

Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/168835
 
201 次点击