您現在的位置是:首頁 > 綜合

Python 速度慢,試試這個方法提高 1000 倍

  • 由 CSDN 發表于 綜合
  • 2021-08-11
簡介var rand = new Random

龜兔調節旋鈕會掉怎麼辦

Python 速度慢,試試這個方法提高 1000 倍

作者 | Andrew Zhu

譯者 | 蘇本如

出品 | CSDN(ID:CSDNnews)

Python 速度慢,試試這個方法提高 1000 倍

龜兔比賽(我6歲兒子 Charles Zhu 的繪畫作品)

Python 速度慢,試試這個方法提高 1000 倍

人們一直詬病 Python 程式的速度很慢,它到底有多慢呢?

在每次的程式語言速度競賽中,Python 的名次通常都比較墊底。有人解釋這是因為 Python 是一種解釋型語言(程式碼無需編譯即可執行),而所有的解釋型程式語言執行速度都很慢。然而,我們知道 Java 也是一種解釋型語言,它的位元組碼是由 JVM 解釋的。而在這個基準測試速度比較頁面上的結果卻顯示:Java 要比 Python 的速度快得多。

下面是一個可以用來演示 Python 速度慢的示例。它使用傳統的 for 迴圈來產生一個數的倒數:

import numpy as np

np。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 速度慢,試試這個方法提高 1000 倍

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 程式的效能呢?

Python 速度慢,試試這個方法提高 1000 倍

答案是:使用 NumPy 通用函式

與 Python 列表(list)不同,NumPy 陣列是圍繞 C 陣列構建的物件。NumPy 陣列訪問項不需要任何步驟來檢查型別。這給我們找到解決方案指明瞭方向:使用 NumPy

通用函式

(亦即UFunc)。

Python 速度慢,試試這個方法提高 1000 倍

簡而言之,UFunc 是一種可以直接對整個陣列進行算術運算的方法。下面我們將前面那個慢速的 Python 示例改寫為 UFunc 版本,它就像下面這樣:

import numpy as np

np。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 還有許多其他運算子(如下圖示)。

Python 速度慢,試試這個方法提高 1000 倍

點選這裡可以找到所有 Ufunc 運算(操作)符。

Python 速度慢,試試這個方法提高 1000 倍

總結

對於那些使用 Python 的人來說,使用 Python 處理資料和數字的可能性很大。這些資料可以儲存在 NumPy 或 Pandas DataFrame中,因為DataFrame 是基於 NumPy 實現的。所以 Ufunc 也可以使用。

UFunc 使我們能夠以超越幾個數量級的更快速度在 Python 中執行重複操作。最慢的 Python 甚至可以跑得 C 語言更快。這一點太讓人激動了。

Python 速度慢,試試這個方法提高 1000 倍

附錄— C,C#,Java 和 NodeJS 的測試程式碼

C 語言:

#include

#include

#include

int main{

struct timeval stop, start;

int length = 1000000;

int rand_array[length];

float output_array[length];

for(int i = 0; i

rand_array[i] = rand;

}

gettimeofday(&start, );

for(int i = 0; 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

rand_array[i] = rand。Next;

//Console。WriteLine(rand_array[i]);

}

long start = DateTimeOffset。Now。ToUnixTimeMilliseconds;

for(int i =0;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

rand_array[i] = rand。nextLong;

}

long start = System。currentTimeMillis;

for(int i = 0;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

rand_array[i] = Math。floor(Math。random*10000000);

}

let start = (new Date)。getMilliseconds;

for(var i=0;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翻譯,轉載請註明來源。

Python 速度慢,試試這個方法提高 1000 倍

4月20日晚八點,歡迎來到CSDN悅讀時間直播間,與四位大咖一起探索UNIX傳奇往事的啟示,圍觀《UNIX傳奇》新書釋出會!

Python 速度慢,試試這個方法提高 1000 倍

Top