<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          Python 速度慢,試試這個(gè)方法提高 1000 倍

          共 4420字,需瀏覽 9分鐘

           ·

          2021-05-02 10:11

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


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


          在每次的編程語(yǔ)言速度競(jìng)賽中,Python 的名次通常都比較墊底。有人解釋這是因?yàn)?Python 是一種解釋型語(yǔ)言(代碼無(wú)需編譯即可執(zhí)行),而所有的解釋型編程語(yǔ)言執(zhí)行速度都很慢。然而,我們知道 Java 也是一種解釋型語(yǔ)言,它的字節(jié)碼是由 JVM 解釋的。而在這個(gè)基準(zhǔn)測(cè)試速度比較頁(yè)面上的結(jié)果卻顯示:Java 要比 Python 的速度快得多。

          下面是一個(gè)可以用來(lái)演示 Python 速度慢的示例。它使用傳統(tǒng)的 for 循環(huán)來(lái)產(chǎn)生一個(gè)數(shù)的倒數(shù):

          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)

          結(jié)果顯示:

          每個(gè)循環(huán)平均耗時(shí)3.37秒(標(biāo)準(zhǔn)偏差±582毫秒)(共計(jì)運(yùn)行了7次程序,每次一個(gè)循環(huán))

          計(jì)算 1,000,000 個(gè)倒數(shù)竟然需要 3.37 秒。使用 C 語(yǔ)言執(zhí)行同樣的運(yùn)算只需要不到一眨眼的工夫:9 毫秒;C# 需要 19 毫秒;Nodejs 需要 26 毫秒;Java 僅僅需要 5 毫秒!而 Python 竟然用了讓人懷疑人生的 3.37秒(它到底做了些什么)?。ㄗⅲ涸诒疚牡淖詈?,我附上了所有語(yǔ)言的測(cè)試代碼)。



          2、Python 速度緩慢的根本原因


          我們通常把 Python 稱(chēng)為一種動(dòng)態(tài)類(lèi)型編程語(yǔ)言。而 Python 程序中的一切變量都是以對(duì)象的形式存在,換句話(huà)說(shuō),每次 Python 代碼處理數(shù)據(jù)時(shí),都需要進(jìn)行對(duì)象拆箱操作,以確定對(duì)象的具體類(lèi)型。在 for 循環(huán)內(nèi)部,每次循環(huán)都需要拆箱對(duì)象,檢查類(lèi)型并計(jì)算倒數(shù)。那3秒鐘的時(shí)間都在類(lèi)型檢查中浪費(fèi)了。

          C 語(yǔ)言和其他傳統(tǒng)的編程語(yǔ)言則不同,它們對(duì)數(shù)據(jù)的訪(fǎng)問(wèn)是直接的。但在 Python 中,大量的 CPU 時(shí)間都用在了類(lèi)型檢查上。

          即使是一個(gè)簡(jiǎn)單的賦值操作也會(huì)花費(fèi)很長(zhǎng)的時(shí)間。如:

          a = 1

          這個(gè)簡(jiǎn)單的賦值操作,它需要如下兩個(gè)步驟:

          • 步驟 1:將 a->PyObject_HEAD->typecode 設(shè)置為 Integer 類(lèi)型.

          • 步驟 2. 將值 1 賦值 a (a->val =1).

          關(guān)于 Python 為什么速度慢的更多信息,Jake 寫(xiě)的這篇精彩文章值得一讀:Why Python is Slow: Looking Under the Hood

          那么,有沒(méi)有一種方法可以繞過(guò)類(lèi)型檢查,從而提高 Python 程序的性能呢?



          3、答案是:使用 NumPy 通用函數(shù)


          與 Python 列表(list)不同,NumPy 數(shù)組是圍繞 C 數(shù)組構(gòu)建的對(duì)象。NumPy 數(shù)組訪(fǎng)問(wèn)項(xiàng)不需要任何步驟來(lái)檢查類(lèi)型。這給我們找到解決方案指明了方向:使用 NumPy 通用函數(shù)(亦即UFunc)。

          簡(jiǎn)而言之,UFunc 是一種可以直接對(duì)整個(gè)數(shù)組進(jìn)行算術(shù)運(yùn)算的方法。下面我們將前面那個(gè)慢速的 Python 示例改寫(xiě)為 UFunc 版本,它就像下面這樣:

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

          改寫(xiě)后的代碼不僅提高了速度,而且代碼變得更短。猜猜現(xiàn)在這個(gè)程序執(zhí)行要花多少時(shí)間?它比我上面提到的最快的語(yǔ)言快了2.7毫秒

          每個(gè)循環(huán)平均耗時(shí)2.71毫秒(標(biāo)準(zhǔn)偏差±50.8微秒)(共運(yùn)行了7次程序,每次循環(huán)100個(gè))

          返回代碼,關(guān)鍵是 1.0/values 這一行。這里的 values 不是一個(gè)數(shù)字,而是一個(gè) NumPy 數(shù)組。和除法運(yùn)算符一樣,Numpy 還有許多其他運(yùn)算符(如下圖示)。

          點(diǎn)擊這里可以找到所有 Ufunc 運(yùn)算(操作)符。



          4、總結(jié)


          對(duì)于那些使用 Python 的人來(lái)說(shuō),使用 Python 處理數(shù)據(jù)和數(shù)字的可能性很大。這些數(shù)據(jù)可以存儲(chǔ)在 NumPy 或 Pandas DataFrame中,因?yàn)镈ataFrame 是基于 NumPy 實(shí)現(xiàn)的。所以 Ufunc 也可以使用。

          UFunc 使我們能夠以超越幾個(gè)數(shù)量級(jí)的更快速度在 Python 中執(zhí)行重復(fù)操作。最慢的 Python 甚至可以跑得 C 語(yǔ)言更快。這一點(diǎn)太讓人激動(dòng)了。



          5、附錄— C,C#,Java 和 NodeJS 的測(cè)試代碼


          C 語(yǔ)言:

          #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, NULL);
          for(int i = 0; i<length; i++){
          output_array[i] = 1.0/(rand_array[i]*1.0);
          }
          gettimeofday(&stop, NULL);
          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

          文章轉(zhuǎn)載:Python程序員

          (版權(quán)歸原作者所有,侵刪)

          瀏覽 67
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  成人做爰A片免费看网站网豆传媒 | 久久九九er精品在线 | 奇米av网 | 欧美性受XXXX黑人XYX性爽冫 | 黄色精品|