為什麼你寫的Python運行的那麼慢呢?

来源:http://www.cnblogs.com/shouce/archive/2016/01/06/5104355.html
-Advertisement-
Play Games

當在網上問為什麼Python比C語言更慢,回答最多的就是Python中有動態類型。然而,動態類型確實會在性能方面有影響,但是這並不是主要原因。 動態類型(像Python一樣的主要編程語言都一樣)使得編譯器很難優化性能。動態使得每次執行都可能很不同,編譯器難以優化。然而,正如Alex在談話中提到的,....


當在網上問為什麼Python比C語言更慢,回答最多的就是Python中有動態類型。然而,動態類型確實會在性能方面有影響,但是這並不是主要原因。

  動態類型(像Python一樣的主要編程語言都一樣)使得編譯器很難優化性能。動態使得每次執行都可能很不同,編譯器難以優化。然而,正如Alex在談話中提到的,我們花費了數年的時間來研究究竟在運行時進行類型檢查的最好的辦法是什麼。但是沒什麼進展。

  在現實中,在C語言和Python在運行時的巨大的不同是由於數據結構和演算法的不同。有時程式員也沒有註意到這一點。

用Python寫不同的代碼

  讓我們用一個Alex提到的實例來說明問題。一個Python程式員可能很喜歡用下麵的例子表示一個平面上的點:

1 point = {'x': 0, 'y': 0}

  這種方法很易讀,容易編碼,形式很優雅。

  另一個方面,一個C語言程式員可能使用結構體來表示平面上的點:

1 2 3 4 struct Point {    int x;    int y; };

  儘管這種方法也和Python能一樣的工作並且都是很優雅的,但這是完全不同的數據結構。這裡我們告訴了編譯器,我們有兩個欄位x和y。知道了這兩個欄位的類型,編譯器將分配一塊連續的記憶體來儲存這兩個數據。換一句話說,就像一個數組一樣。任何時間,編譯器都知道給定的x和y在哪裡。我們可以很容易地訪問這些數據,就像是訪問某些常數據一樣。

  Python使用哈希散列的方法來解決類似的問題。所以編譯器不能簡單地分配連續記憶體存儲x和y來處理這些問題。由於我們在其中任意的地方都可能出現這些鍵。如果我們想的話,我們也可能刪除這些鍵。編譯器必須要使用哈希函數來映射到你可能讓他指向的任何存儲單元。不用說,這些函數增加了處理時間。儘管也許減緩的很小,但是足可以拖慢你的代碼,尤其是這種情況如果很多的時候。

  如果就是想將Python翻譯成C語言的話,可能就像下麵這樣:

1 2 3 std::hash_set<span> point; point[“x”] = x point[“y”] = y</span>

  看這個代碼片段,好像就是語言的設計者他們自己故意儘力使哈希表複雜,因此儘管是正確的,但沒有人使用。由於這個原因,寫C語言的人可能認為這是不可思議的,但為什麼在Python就是可以接受的呢?

  原因就是寫Python代碼的人的“dictionaries are lightweight objects”這種心態。看下麵的代碼,這在Python中最接近C語言結構體:

1 2 3 4 class Point(object):      x, y = None, None      def __init__(self, x, y):           self.x, self.y = x, y

         

  這對編譯器是有用的,就像是C語言的結構體。例如第二行,我們明確告訴編譯器但我們創造一個對象時我們總是至少需要兩個數據段,我們希望編譯器處理這個問題。

  不幸的是這種標準的Python被叫做CPthon,不能總被使用。在我的機器上,下麵的代碼要執行186毫秒:

1 2 3 4 5 6 def sum_(points):     sum_x, sum_y = 0, 0     for point in points:         sum_x += point['x']         sum_y += point['y']     return sum_x, sum_y

  在我的機器上,用point.x代替point['x']會花費201毫秒。也就是說,會慢了8%。

  在CPthon中,point.x通常就是被處理成dict(point)['x']。這意味著帶著點的class仍然像以前一樣使用字典(dictionary)的方法查找。這樣的話,就很容易看出為什麼directionary的方法被看為“輕量級的”。

  一些Python寫的代碼就是為了效率而設計的,例如PyPy,能很快地執行。如果不使用Python而是使用PyPy,同樣的代碼片段執行時間分別是21.6和3.75毫秒。這種方法相比CPython在JIT-capable編譯情況下結果都是令人滿意的。換一句話說,PyPy能正確地使用數據結構。

  我希望你再一次看這個最短時間3.75毫秒。這個數字表明我們能在一秒進行266000次運算,這些事來自Python的,其中有動態綁定,monkey-patching(在不改變源代碼的情況下擴展或修改動態語言運行時代碼的方法)等。所有的這些,都是在編碼和實現中使用了更好的數據結構。下一次當你在用Python寫一行代碼時,想一想你在使用什麼數據結構,顯示的還是隱式的,考慮一下是否有更好的辦法。這就是你用C語言寫程式時考慮的,不是嗎?

  最後,我願意相信這個文章是表明為什麼Python是一個有前途的語言的一個清楚的例子(或者是類似的語言)。這表明瞭標準的Python實現,這裡的CPython僅僅是作為一個參考,它從來就不是被設計用來更快地執行的。正如我們今天可以看到的,像PyPy一樣的演算法實現是可以優化你的代碼到一個很好的長度。隨著語言的自然發展,這些優化是可能的。我們僅僅用Python編程過23年,那麼如果像C語言一樣有42年的發展,Python會是什麼樣子呢?

  1、有人也許會爭辯說collections.namedtuple()是更接近於C語言的結構體,這是對的,但我們不要過分將事情複雜化,我們的重點是有效。

  2、為了更清楚python是怎樣工作的,請參考python文檔。

  原文 lukauskas.co.uk


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 今天在上班路上看到一篇互聯網網路協議的文章感覺寫的的是相當好,圖文兼備,通俗易懂,好東西嘛當然要留下了,也在這給大家分享分享!
  • 最近在使用python做介面測試,發現python中http請求方法有很多種,現彙總如下:一、python自帶庫----urllib2python自帶庫urllib2使用的比較多,簡單使用如下:import urllib2response = urllib2.urlopen('http://loca...
  • Demo:import java.nio.file.Path;import java.nio.file.Paths;public class PathInfoTest { public static void main(String[] args) { /...
  • 支付寶介面使用文檔說明 支付寶非同步通知(notify_url)與return_url.現支付寶的通知有兩類。A伺服器通知,對應的參數為notify_url,支付寶通知使用POST方式B頁面跳轉通知,對應的參數為return_url,支付寶通知使用GET方式 (通知地址不需要像以前一樣去賬戶內設置,而...
  • 在實際編程中,往往存在著這樣的“數據集”,它們的數值在程式中是穩定的,而且“數據集”中的元素是有限的。 例如星期一到星期日七個數據元素組成了一周的“數據集”,春夏秋冬四個數據元素組成了四季的“數據集”。 enum 的全稱為 enumeration, 是 JDK 1.5 中引入的新特性,存放在...
  • Demo:import java.nio.file.Path;import java.nio.file.Paths;/** * @author jinxing * @系統 MAC OS X * @用例1 [使用]絕對路徑 * @用例2 [使用]相對路徑 * @用例3 相對路徑[轉換成]絕對路徑 * ...
  • 有的小伙伴會問:博主,沒有Mac怎麼學Swift語言呢,我想學Swift,但前提得買個Mac。非也,非也。如果你想瞭解或者初步學習Swift語言的話,你可以登錄這個網站:http://swiftstub.com/。該網站可以線上運行出代碼結果,也可以說這是一個線上的Playground。你可以...
  • Path通常代表文件系統中的位置,能瀏覽任何類型的文件系統,包括zip歸檔文件系統;文件系統中的幾個概念:目錄樹、根目錄、絕對路徑、相對路徑;NIO.2中的Path是一個抽象構造,你所創建和處理的Path可以不馬上綁定到對應的物理位置上;——物理文件系統的處理通常由Files輔助類實現;基礎類類說明...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...