簡體   English   中英

為什么 Python 程序通常比 C 或 C++ 中編寫的等效程序慢?

[英]Why are Python Programs often slower than the Equivalent Program Written in C or C++?

為什么 Python 看起來平均比 C/C++ 慢? 我學習了 Python 作為我的第一門編程語言,但我才剛剛開始使用 C,我已經覺得我可以看到明顯的區別。

Python 是比 C 更高級的語言,這意味着它從你那里抽象出計算機的細節——內存管理、指針等,並允許你以更接近人類思維方式的方式編寫程序。

如果僅測量執行時間,C 代碼的運行速度通常比 Python 代碼快 10 到 100 倍。 但是,如果您還包括開發時間,Python 通常會勝過 C。對於許多項目而言,開發時間遠比運行時性能更重要。 更長的開發時間直接轉化為額外的成本、更少的功能和更慢的上市時間。

Python 代碼執行速度較慢的內部原因是代碼在運行時被解釋,而不是在編譯時被編譯為本機代碼。

其他解釋性語言(例如 Java 字節碼和 .NET 字節碼)的運行速度比 Python 快,因為標准發行版包括一個JIT 編譯器,可在運行時將字節碼編譯為本機代碼。 CPython 還沒有 JIT 編譯器的原因是因為 Python 的動態特性使其難以編寫。 正在編寫更快的 Python 運行時的工作正在進行中,因此您應該期望將來性能差距會縮小,但標准 Python 發行版包含強大的 JIT 編譯器可能還需要一段時間。

CPython 特別慢,因為它沒有即時優化器(因為它是參考實現並且在某些情況下選擇簡單性而不是性能)。 Unladen Swallow是一個將 LLVM 支持的 JIT 添加到 CPython 中的項目,並實現了巨大的加速。 Jython 和 IronPython 可能比 CPython 快得多,而且它們得到了高度優化的虛擬機(JVM 和 .NET CLR)的支持。

然而,可以說讓 Python 變慢的一件事是它是動態類型的,並且每個屬性訪問都有大量的查找。

例如,在對象A上調用f將導致可能在__dict__查找,調用__getattr__等,然后最終在可調用對象f上調用__call__

關於動態類型,如果您知道要處理的數據類型,則可以進行許多優化。 例如,在 Java 或 C 中,如果您有一個想要求和的整數數組,則最終的匯編代碼可以很簡單,只需獲取索引i處的值,將其添加到accumulator ,然后遞增i

在 Python 中,很難使代碼達到最佳狀態。 假設您有一個包含int的列表子類對象。 在添加任何之前,Python 必須調用list.__getitem__(i) ,然后通過調用accumulator.__add__(n)其添加到“累加器”,然后重復。 這里可能會發生大量的替代查找,因為另一個線程可能已經改變了例如__getitem__方法、列表實例的字典或類的字典,在調用 add 或 getitem 之間。 即使在本地命名空間中找到累加器和列表(以及您正在使用的任何變量)也會導致 dict 查找。 當使用任何用戶定義的對象時,同樣的開銷也適用,盡管對於某些內置類型,它會有所減輕。

還值得注意的是,諸如 bigint(Python 3 中的 int,Python 2.x 中的 long)、list、set、dict 等原始類型是人們在 Python 中大量使用的。 這些對象上有大量內置操作已經足夠優化。 例如,對於上面的示例,您只需調用sum(list)而不是使用累加器和索引。 堅持這些,並使用 int/float/complex 進行一些數字運算,您通常不會遇到速度問題,如果這樣做,可能會有一個小的時間關鍵單元(例如 SHA2 摘要函數),您可以只需移出 C(或 Java 代碼,在 Jython 中)。 事實是,當您編寫 C 或 C++ 代碼時,您將浪費大量時間做幾秒鍾/幾行 Python 代碼即可完成的事情。 我想說這種權衡總是值得的,除非您在做嵌入式或實時編程之類的事情並且負擔不起。

編譯與解釋在這里並不重要:Python是經過編譯的,對於任何非平凡程序來說,它只是運行時成本的一小部分。

主要成本是:缺少與本機整數相對應的整數類型(使所有整數運算的成本大大提高),缺少靜態類型(這使得方法的解析更加困難,並且意味着必須檢查值的類型在運行時),以及缺少未裝箱的值(這會減少內存使用量,並且可以避免一定程度的間接性)。

並不是說這些事情中的任何一個在 Python 中都不可能或不能提高效率,而是選擇了有利於程序員的便利性和靈活性,以及​​語言的簡潔性而不是運行時速度。 其中一些成本可以通過巧妙的 JIT 編譯來克服,但 Python 提供的好處總是需要付出一些代價。

python 和 C 之間的區別是解釋(字節碼)和編譯(本地)語言之間的常見區別。 就我個人而言,我並不認為 python 很慢,它管理得很好。 如果您嘗試在其領域之外使用它,當然,它會更慢。 但是為此,您可以為 python 編寫 C 擴展,它將時間關鍵算法放在本機代碼中,使其更快。

將 C/C++ 與 Python 進行比較並不是一個公平的比較。 就像將 F1 賽車與多用途卡車進行比較。

令人驚訝的是,與其他動態語言的同行相比,Python 的速度有多快。 雖然該方法通常被認為有缺陷,但請查看計算機語言基准游戲以了解類似算法的相對語言速度。

與 Perl、Ruby 和 C# 的比較更加“公平”

Python 通常作為腳本語言實現。 這意味着它通過一個解釋器,這意味着它可以將代碼即時翻譯成機器語言,而不是從一開始就讓可執行文件全部使用機器語言。 因此,除了執行代碼之外,它還必須支付翻譯代碼的成本。 即使對於 CPython 也是如此,即使它編譯為更接近機器語言的字節碼,因此可以更快地翻譯。 Python 還帶來了一些非常有用的運行時特性,比如動態類型,但即使在沒有大量運行時成本的最有效的實現上,這些東西通常也無法實現。

如果您正在執行諸如編寫着色器之類的處理器密集型工作,那么 Python 比 C++ 慢 200 倍左右的情況並不少見。 如果您使用 CPython,那段時間可以減少一半,但仍然遠遠不夠快。 所有這些小東西都是有代價的。 有很多基准可以證明這一點,這里有一個特別好的基准。 正如頭版所承認的,基准是有缺陷的。 它們都是由用戶提交的,他們盡最大努力用他們選擇的語言編寫高效的代碼,但它為您提供了一個很好的總體思路。

如果您關心效率,我建議您嘗試將兩者混合在一起:這樣您就可以兩全其美。 我主要是一名 C++ 程序員,但我認為很多人傾向於在 C++ 中編寫太多普通的高級代碼,而這樣做很麻煩(編譯時間只是一個例子)。 將腳本語言與像 C/C++ 這樣更接近金屬的高效語言混合在一起,確實是平衡程序員效率(生產力)和處理效率的方法。

除了已經發布的答案之外,還有一件事是 python 能夠在運行時更改您無法更改的內容,例如 C。您可以隨時向類添加成員函數。 此外,python 的動態特性使得無法說明將傳遞給函數的參數類型,這反過來又使優化變得更加困難。

RPython似乎是解決優化問題的一種方式。

盡管如此,它可能不會接近 C 在數字運算等方面的性能。

C 和 C++ 編譯為本機代碼——也就是說,它們直接在 CPU 上運行。 Python 是一種解釋型語言,這意味着您編寫的 Python 代碼必須經過很多很多抽象階段才能成為可執行的機器代碼。

Python 是一種高級編程語言。 以下是python腳本的運行方式:

在此處輸入圖片說明

首先將python源代碼編譯成Byte Code 是的,你明白我的意思了! 雖然 Python 是一種解釋型語言,但它首先被編譯成字節碼。 這個字節碼然后由Python 虛擬機(PVM) 解釋和執行。

這種編譯和執行使 Python 比其他低級語言(如 C/C++)慢。 在 C/C++ 等語言中,源代碼被編譯成二進制代碼,可以直接由 CPU 執行,因此其執行效率比 Python 高。

在此處輸入圖片說明

這個答案適用於 python3。 大多數人不知道只要使用 import 語句就會發生類似 JIT 的編譯。 CPython 將搜索導入的源文件 (.py),注意修改日期,然后在名為“_ _ pycache _ _”(dunder pycache dunder)的子文件夾中查找編譯為字節碼的文件 (.pyc)。 如果一切都匹配,那么您的程序將使用該字節碼文件,直到發生某些變化(您更改源文件或升級 Python)

但這不會發生在主程序上,它通常是從 BASH shell 以交互方式或通過方式啟動的。 這是一個例子:

#!/usr/bin/python3
# title : /var/www/cgi-bin/name2.py
# author: Neil Rieck
# edit  : 2019-10-19
# ==================
import name3  # name3.py will be cache-checked and/or compiled
import name4  # name4.py will be cache-checked and/or compiled
import name5  # name5.py will be cache-checked and/or compiled
#
def main():
    #
    # code that uses the imported libraries goes here
    #
if __name__ == "__main__":
    main()
#

一旦執行,編譯后的 output 代碼將被丟棄。 但是,如果您通過如下導入語句啟動,您的主要 python 程序將被編譯:

#!/usr/bin/python3
# title : /var/www/cgi-bin/name1
# author: Neil Rieck
# edit  : 2019-10-19
# ==================
import name2    # name2.py will be cache-checked and/or compiled
#name2.main()   #

現在注意事項:

  1. 如果您在 Apache 區域中以交互方式測試代碼,您編譯的文件可能會保存 Apache 無法讀取(或寫入重新編譯)的權限
  2. 一些人聲稱子文件夾“_ _ pycache _ _”(dunder pycache dunder)需要在 Apache 配置中可用
  3. SELinux 會允許 CPython 寫入子文件夾嗎(這是 CentOS-7.5 的問題,但我相信補丁已經可用)

最后一點。 您可以自己訪問編譯器,生成 pyc 文件,然后更改保護位作為我列出的任何警告的變通方法。 這里有兩個例子:

method #1
=========
python3
import py_compile
py_compile("name1.py")
exit()

method #2
=========
python3 -m py_compile name1.py

python 是解釋性語言,沒有被編譯,也沒有與 CPU 硬件結合

但我有一個解決方案來增加 python 作為一種更快的編程語言

1.Use python3 for run and code python command like Ubuntu or any Linux distro use python3 main.py and update regularly your python so you python3 framework modules and libraries i will suggest use pip 3.

2.Use [Numba][1] python framework with JIT compiler this framework use for data visualization but you can use for any program this framework use GPU acceleration of your program.

3.Use [Profiler optimizing][1] so this use for see with function or syntax for bit longer or faster also have use full to change syntax as a faster for python its very god and work full so this give a with function or syntax using much more time execution of code.

4.Use multi threading so making multiprocessing of program for python so use CPU cores and threads so this make your code much more faster.

5.Using C,C#,C++ increasing python much more faster i think its called parallel programing use like a [cpython][1] .

6.Debug your code for test your code to make not bug in your code so then you will get little bit your code faster also have one more thing Application logging is for debugging code.

and them some low things that makes your code faster:

 1.Know the basic data structures for using good syntax use make best code.

 2.make a best code have Reduce memory footprinting.

 3.Use builtin functions and libraries.

 4.Move calculations outside the loop.

 5.keep your code base small.

所以使用這個東西然后讓你的代碼更快是的所以使用這個python不是一種緩慢的編程語言

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM