(今天實習面試又問道這個問題了,答的不是很好= = )
靜態語言和動態語言
常見的語言按照動態語言和靜態語言來分類:
-
靜態語言:
java, c, c++, go等
強類型語言(靜態類型語言)是指需要進行變量/對象類型聲明的語言,一般情況下需要編譯執行。強類型語言是一旦變量的類型被確定,就不能轉化的語言。 -
動態語言:
python, javascript, php, ruby等
弱類型語言(動態類型語言)是指不需要進行變量/對象類型聲明的語言,一般情況下不需要編譯(但也有編譯型的)。動態類型語言是在運行時確定數據類型的語言。變量使用之前不需要類型聲明,通常變量的類型是被賦值的那個值的類型。
弱類型語言則反之,一個變量的類型是由其應用上下文確定的。 -
靜態語言優勢
由於類型的強制聲明,使得IDE有很強的代碼感知能力,故,在實現復雜的業務邏輯、開發大型商業系統、以及那些生命周期很長的應用中,依托IDE對系統的開發很有保障;
由於靜態語言相對比較封閉,使得第三方開發包對代碼的侵害性可以降到最低;
- 動態語言的優勢:
- 在靜態語言中的一些高級概念,如java中的反射以及基於反射實現的AOP, 這些概念對java初學者以及只有一兩年工作經驗的人來說,這幾個概念是很難理解的,更不用說如何去自己實現。如果大家使用過AOP的話就會明白這幾個概念從理解到熟練使用是比較難的, 而且開發效率會比較低,盡管同學可能會說“其實使用起來還是很簡單啊”, 那可能是因為你沒有用過動態語言中的裝飾器。
- 動態語言中對於java中的AOP這種概念直接使用裝飾器就可以完成而且是python語言本身的一部分。並不像java中還需要引入第三方來完成。
- 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 同樣也使用了引用計數,但是引用計數存在這些缺點:
- 頻繁更新引用計數會降低運行效率
- 引用計數無法解決循環引用問題
Python 在引用計數機制的基礎上,使用了主流垃圾收集技術中的標記——清除和分代收集兩種技術。
