1. 程式人生 > >Python 和 Java的對比

Python 和 Java的對比

(今天實習面試又問道這個問題了,答的不是很好= = )

靜態語言和動態語言

常見的語言按照動態語言和靜態語言來分類:

  • 靜態語言:
    java, c, c++, go等
    強型別語言(靜態型別語言)是指需要進行變數/物件型別宣告的語言,一般情況下需要編譯執行。強型別語言是一旦變數的型別被確定,就不能轉化的語言。
  • 動態語言:
    python, javascript, php, ruby等
    弱型別語言(動態型別語言)是指不需要進行變數/物件型別宣告的語言,一般情況下不需要編譯(但也有編譯型的)。動態型別語言是在執行時確定資料型別的語言。變數使用之前不需要型別宣告,通常變數的型別是被賦值的那個值的型別。
    弱型別語言則反之,一個變數的型別是由其應用上下文確定的。

  • 靜態語言優勢

    由於型別的強制宣告,使得IDE有很強的程式碼感知能力,故,在實現複雜的業務邏輯、開發大型商業系統、以及那些生命週期很長的應用中,依託IDE對系統的開發很有保障;
    由於靜態語言相對比較封閉,使得第三方開發包對程式碼的侵害性可以降到最低;

  • 動態語言的優勢:

    1. 在靜態語言中的一些高階概念,如java中的反射以及基於反射實現的AOP, 這些概念對java初學者以及只有一兩年工作經驗的人來說,這幾個概念是很難理解的,更不用說如何去自己實現。如果大家使用過AOP的話就會明白這幾個概念從理解到熟練使用是比較難的, 而且開發效率會比較低,儘管同學可能會說“其實使用起來還是很簡單啊”, 那可能是因為你沒有用過動態語言中的裝飾器。
    2. 動態語言中對於java中的AOP這種概念直接使用裝飾器就可以完成而且是python語言本身的一部分。並不像java中還需要引入第三方來完成。
    3. python能輕鬆完成這些正是由於python是一門動態語言, 動態語言的特性使得大家去自己控制整個類的初始化以及動態去改變物件變的異常簡單, 這些特性使得動態語言的靈活性遠遠超過靜態語言。

解釋型語言和編譯型語言

這裡的解釋執行是相對於編譯執行而言的。我們都知道,使用C/C++之類的編譯性語言編寫的程式,是需要從原始檔轉換成計算機使用的機器語言,經過連結器連結之後形成了二進位制的可執行檔案。執行該程式的時候,就可以把二進位制程式從硬碟載入到記憶體中並執行。

  • python的執行過程和Java是類似的:
    python直譯器將原始碼轉換為位元組碼,然後再由python直譯器來執行這些位元組碼。

一個具體的Python程式的執行過程:

 - 執行python程式後,將會啟動 Python 的直譯器,然後將python程式編譯成一個位元組碼物件 PyCodeObject。
 - 在執行期間,編譯結果也就是 PyCodeObject 物件,只會存在於記憶體中,而當這個模組的 Python 程式碼執行完後,就會將編譯結果儲存到了 pyc 檔案中,這樣下次就不用編譯,直接載入到記憶體中。pyc 檔案只是 PyCodeObject 物件在硬碟上的表現形式。
 - 這個 PyCodeObject 物件包含了 Python 原始碼中的字串,常量值,以及通過語法解析後編譯生成的位元組碼指令。PyCodeObject 物件還會儲存這些位元組碼指令與原始程式碼行號的對應關係,這樣當出現異常時,就能指明位於哪一行的程式碼。
  • Java也是先編譯成位元組碼,再去執行
    直譯器,java很特殊,java是需要編譯的,但是沒有直接編譯成機器語言,而是編譯成位元組碼,然後在Java虛擬機器上用解釋的方式執行位元組碼。Python也使用了類似的方式,先將python編譯成python位元組碼,然後由一個專門的python位元組碼直譯器負責解釋執行位元組碼。

Python 的GIL

GIL的全稱是Global Interpreter Lock(全域性直譯器鎖)來源是python設計之初的考慮,為了資料安全所做的決定。

在Python多執行緒下,每個執行緒的執行方式:
1.獲取GIL
2.執行程式碼直到sleep或者是python虛擬機器將其掛起。
3.釋放GIL

可見,某個執行緒想要執行,必須先拿到GIL,我們可以把GIL看作是“通行證”,並且在一個python程序中,GIL只有一個。拿不到通行證的執行緒,就不允許進入CPU執行。
而每次釋放GIL鎖,執行緒進行鎖競爭、切換執行緒,會消耗資源。並且由於GIL鎖存在,python裡一個程序永遠只能同時執行一個執行緒(拿到GIL的執行緒才能執行),這就是為什麼在多核CPU上,python的多執行緒效率並不高。
每個程序有各自獨立的GIL,互不干擾,這樣就可以真正意義上的並行執行,所以在python中,多程序的執行效率優於多執行緒(僅僅針對多核CPU而言)。

由於 GIL 的存在,Python 的多執行緒效能十分低下,無法發揮多核 CPU 的優勢,效能甚至不如單執行緒。因此如果你想用到多核 CPU,一個建議是使用多程序或者協程

Python垃圾回收

在講到垃圾回收的時候,通常會使用引用計數的模型,這是一種最直觀,最簡單的垃圾收集技術。Python 同樣也使用了引用計數,但是引用計數存在這些缺點:

  1. 頻繁更新引用計數會降低執行效率
  2. 引用計數無法解決迴圈引用問題

Python 在引用計數機制的基礎上,使用了主流垃圾收集技術中的標記——清除和分代收集兩種技術。