百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 热门文章 > 正文

Python 速度慢,试试这个方法提高 1000 倍

bigegpt 2024-08-08 11:54 2 浏览

作者 | Andrew Zhu
译者 | 苏本如
出品 | CSDN(ID:CSDNnews)

龟兔比赛(我6岁儿子 Charles Zhu 的绘画作品)


人们一直诟病 Python 程序的速度很慢,它到底有多慢呢?


在每次的编程语言速度竞赛中,Python 的名次通常都比较垫底。有人解释这是因为 Python 是一种解释型语言(代码无需编译即可执行),而所有的解释型编程语言执行速度都很慢。然而,我们知道 Java 也是一种解释型语言,它的字节码是由 JVM 解释的。而在这个基准测试速度比较页面上的结果却显示:Java 要比 Python 的速度快得多。

下面是一个可以用来演示 Python 速度慢的示例。它使用传统的 for 循环来产生一个数的倒数:

import numpy as npnp.random.seed(0)values = np.random.randint(1, 100, size=1000000)def get_reciprocal(values):output = np.empty(len(values))for i in range(len(values)):output[i] = 1.0/values[i]%timeit get_reciprocal(values)

结果显示:

每个循环平均耗时3.37秒(标准偏差±582毫秒)(共计运行了7次程序,每次一个循环)

计算 1,000,000 个倒数竟然需要 3.37 秒。使用 C 语言执行同样的运算只需要不到一眨眼的工夫:9 毫秒;C# 需要 19 毫秒;Nodejs 需要 26 毫秒;Java 仅仅需要 5 毫秒!而 Python 竟然用了让人怀疑人生的 3.37秒(它到底做了些什么)!(注:在本文的最后,我附上了所有语言的测试代码)。


Python 速度缓慢的根本原因


我们通常把 Python 称为一种动态类型编程语言。而 Python 程序中的一切变量都是以对象的形式存在,换句话说,每次 Python 代码处理数据时,都需要进行对象拆箱操作,以确定对象的具体类型。在 for 循环内部,每次循环都需要拆箱对象,检查类型并计算倒数。那3秒钟的时间都在类型检查中浪费了。

C 语言和其他传统的编程语言则不同,它们对数据的访问是直接的。但在 Python 中,大量的 CPU 时间都用在了类型检查上。

即使是一个简单的赋值操作也会花费很长的时间。如:

a = 1

这个简单的赋值操作,它需要如下两个步骤:

  • 步骤 1:将 a->PyObject_HEAD->typecode 设置为 Integer 类型.

  • 步骤 2. 将值 1 赋值 a (a->val =1).

关于 Python 为什么速度慢的更多信息,Jake 写的这篇精彩文章值得一读:Why Python is Slow: Looking Under the Hood

那么,有没有一种方法可以绕过类型检查,从而提高 Python 程序的性能呢?


答案是:使用 NumPy 通用函数


与 Python 列表(list)不同,NumPy 数组是围绕 C 数组构建的对象。NumPy 数组访问项不需要任何步骤来检查类型。这给我们找到解决方案指明了方向:使用 NumPy 通用函数(亦即UFunc)。

简而言之,UFunc 是一种可以直接对整个数组进行算术运算的方法。下面我们将前面那个慢速的 Python 示例改写为 UFunc 版本,它就像下面这样:

import numpy as npnp.random.seed(0)values = np.random.randint(1, 100, size=1000000)%timeit result = 1.0/values

改写后的代码不仅提高了速度,而且代码变得更短。猜猜现在这个程序执行要花多少时间?它比我上面提到的最快的语言快了2.7毫秒

每个循环平均耗时2.71毫秒(标准偏差±50.8微秒)(共运行了7次程序,每次循环100个)

返回代码,关键是 1.0/values 这一行。这里的 values 不是一个数字,而是一个 NumPy 数组。和除法运算符一样,Numpy 还有许多其他运算符(如下图示)。

点击这里可以找到所有 Ufunc 运算(操作)符。


总结


对于那些使用 Python 的人来说,使用 Python 处理数据和数字的可能性很大。这些数据可以存储在 NumPy 或 Pandas DataFrame中,因为DataFrame 是基于 NumPy 实现的。所以 Ufunc 也可以使用。

UFunc 使我们能够以超越几个数量级的更快速度在 Python 中执行重复操作。最慢的 Python 甚至可以跑得 C 语言更快。这一点太让人激动了。


附录— C,C#,Java 和 NodeJS 的测试代码


C 语言:

#include <stdio.h>#include <stdlib.h>#include <sys/time.h>
int main(){ struct timeval stop, start; int length = 1000000; int rand_array[length]; float output_array[length]; for(int i = 0; i<length; i++){ rand_array[i] = rand(); } gettimeofday(&start, ); for(int i = 0; i<length; i++){ output_array[i] = 1.0/(rand_array[i]*1.0); } gettimeofday(&stop, ); printf("took %lu us\n", (stop.tv_sec - start.tv_sec) * 1000000 + stop.tv_usec - start.tv_usec); printf("done\n"); return 0;}

C#(.net 5.0):

using System;namespace speed_test{ class Program{ static void Main(string[] args){ int length = 1000000; double[] rand_array =new double[length]; double[] output = new double[length]; var rand = new Random(); for(int i =0; i<length;i++){ rand_array[i] = rand.Next(); //Console.WriteLine(rand_array[i]); } long start = DateTimeOffset.Now.ToUnixTimeMilliseconds(); for(int i =0;i<length;i++){ output[i] = 1.0/rand_array[i]; } long end = DateTimeOffset.Now.ToUnixTimeMilliseconds(); Console.WriteLine(end - start); } }}

Java:

import java.util.Random;
public class speed_test { public static void main(String[] args){ int length = 1000000; long[] rand_array = new long[length]; double[] output = new double[length]; Random rand = new Random (); for(int i =0; i<length; i++){ rand_array[i] = rand.nextLong(); } long start = System.currentTimeMillis(); for(int i = 0;i<length; i++){ output[i] = 1.0/rand_array[i]; } long end = System.currentTimeMillis(); System.out.println(end - start); }}

NodeJS:

let length = 1000000;let rand_array = [];let output = [];for(var i=0;i<length;i++){ rand_array[i] = Math.floor(Math.random()*10000000);}let start = (new Date()).getMilliseconds();for(var i=0;i<length;i++){ output[i] = 1.0/rand_array[i];}let end = (new Date()).getMilliseconds();console.log(end - start);

原文链接:https://python.plainenglish.io/a-solution-to-boost-python-speed-1000x-times-c9e7d5be2f40

声明:本文由CSDN翻译,转载请注明来源.

4月20日晚八点,欢迎来到CSDN悦读时间直播间,与四位大咖一起探索UNIX传奇往事的启示,围观《UNIX传奇》新书发布会!


相关推荐

【Docker 新手入门指南】第十章:Dockerfile

Dockerfile是Docker镜像构建的核心配置文件,通过预定义的指令集实现镜像的自动化构建。以下从核心概念、指令详解、最佳实践三方面展开说明,帮助你系统掌握Dockerfile的使用逻...

Windows下最简单的ESP8266_ROTS_ESP-IDF环境搭建与腾讯云SDK编译

前言其实也没啥可说的,只是我感觉ESP-IDF对新手来说很不友好,很容易踩坑,尤其是对业余DIY爱好者搭建环境非常困难,即使有官方文档,或者网上的其他文档,但是还是很容易踩坑,多研究,记住两点就行了,...

python虚拟环境迁移(python虚拟环境conda)

主机A的虚拟环境向主机B迁移。前提条件:主机A和主机B已经安装了virtualenv1.主机A操作如下虚拟环境目录:venv进入虚拟环境:sourcevenv/bin/active(1)记录虚拟环...

Python爬虫进阶教程(二):线程、协程

简介线程线程也叫轻量级进程,它是一个基本的CPU执行单元,也是程序执行过程中的最小单元,由线程ID、程序计数器、寄存器集合和堆栈共同组成。线程的引入减小了程序并发执行时的开销,提高了操作系统的并发性能...

基于网络安全的Docker逃逸(docker)

如何判断当前机器是否为Docker容器环境Metasploit中的checkcontainer模块、(判断是否为虚拟机,checkvm模块)搭配学习教程1.检查根目录下是否存在.dockerenv文...

Python编程语言被纳入浙江高考,小学生都开始学了

今年9月份开始的新学期,浙江省三到九年级信息技术课将同步替换新教材。其中,新初二将新增Python编程课程内容。新高一信息技术编程语言由VB替换为Python,大数据、人工智能、程序设计与算法按照教材...

CentOS 7下安装Python 3.10的完整过程

1.安装相应的编译工具yum-ygroupinstall"Developmenttools"yum-yinstallzlib-develbzip2-develope...

如何在Ubuntu 20.04上部署Odoo 14

Odoo是世界上最受欢迎的多合一商务软件。它提供了一系列业务应用程序,包括CRM,网站,电子商务,计费,会计,制造,仓库,项目管理,库存等等,所有这些都无缝集成在一起。Odoo可以通过几种不同的方式进...

Ubuntu 系统安装 PyTorch 全流程指南

当前环境:Ubuntu22.04,显卡为GeForceRTX3080Ti1、下载显卡驱动驱动网站:https://www.nvidia.com/en-us/drivers/根据自己的显卡型号和...

spark+python环境搭建(python 环境搭建)

最近项目需要用到spark大数据相关技术,周末有空spark环境搭起来...目标spark,python运行环境部署在linux服务器个人通过vscode开发通过远程python解释器执行代码准备...

centos7.9安装最新python-3.11.1(centos安装python环境)

centos7.9安装最新python-3.11.1centos7.9默认安装的是python-2.7.5版本,安全扫描时会有很多漏洞,比如:Python命令注入漏洞(CVE-2015-2010...

Linux系统下,五大步骤安装Python

一、下载Python包网上教程大多是通过官方地址进行下载Python的,但由于国内网络环境问题,会导致下载很慢,所以这里建议通过国内镜像进行下载例如:淘宝镜像http://npm.taobao.or...

centos7上安装python3(centos7安装python3.7.2一键脚本)

centos7上默认安装的是python2,要使用python3则需要自行下载源码编译安装。1.安装依赖yum-ygroupinstall"Developmenttools"...

利用本地数据通过微调方式训练 本地DeepSeek-R1 蒸馏模型

网络上相应的教程基本都基于LLaMA-Factory进行,本文章主要顺着相应的教程一步步实现大模型的微调和训练。训练环境:可自行定义,mac、linux或者window之类的均可以,本文以ma...

【法器篇】天啦噜,库崩了没备份(天啦噜是什么意思?)

背景数据库没有做备份,一天突然由于断电或其他原因导致无法启动了,且设置了innodb_force_recovery=6都无法启动,里面的数据怎么才能恢复出来?本例采用解析建表语句+表空间传输的方式进行...