国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發設計 > 正文

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

2019-11-14 17:31:02
字體:
來源:轉載
供稿:網友

  大約在一年前,也就是2013年在Waza(地名),Alex Gaynor提到了一個很好的話題:為什么用Python、Ruby和javascript寫的程序總是運行的很慢呢?正如他強調的,關鍵就是現在出現了這個問題。換一句話說,盡管現在這種語言很慢,但不意味著沒有解決辦法,不意味著未來會一直這樣。

 

  當在網上問為什么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”這種心態??聪旅娴拇a,這在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


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 宜君县| 洮南市| 无锡市| 佛教| 颍上县| 屏南县| 梅河口市| 南投市| 桑植县| 平泉县| 枞阳县| 平武县| 吴忠市| 阿鲁科尔沁旗| 堆龙德庆县| 睢宁县| 宾川县| 祁连县| 青神县| 龙南县| 雅安市| 崇阳县| 平阳县| 平山县| 府谷县| 长武县| 凌云县| 皋兰县| 万年县| 砚山县| 祁门县| 平果县| 大竹县| 富宁县| 麟游县| 敦煌市| 类乌齐县| 枣阳市| 长沙市| 华池县| 昌都县|