本文目錄一覽:
為什麼python中有了GIL還需要 線程鎖呢?
兩個鎖不是同一個層面的:
1、GIL是限制同一個進程中只有一個線程進入Python解釋器;
2、線程鎖是由於在線程進行數據操作時保證數據操作的安全性(同一個進程中線程之間可以共用信息,如果同時對數據進行操作,則會出現公共數據錯誤);
其實線程鎖完全可以替代GIL,但是Python的後續功能模塊都是加在GIL基礎上的,所以無法更改或去掉GIL, 這就是Python語言最大的bug…只能用多進程或協程改善,或者直接用其他語言寫這部分;
python有哪些特點和優點
顯著的優點
Python 語言擁有諸多的優點,這其中,以下幾個優點特別顯著:
簡單易學:Python語言相對於其他編程語言來說,屬於比較容易學習的一門編程語言,它注重的是如何解決問題而不是編程語言的語法和結構。正是因為Python語言簡單易學,所以,已經有越來越多的初學者選擇Python語言作為編程的入門語言。例如,在浙江省 2017年高中信息技術改革中,《算法與程序設計》課程將使用 Python語言替換原有的VB 語言。
語法優美:Python語言力求代碼簡潔、優美。在Python語言中,採用縮進來標識代碼塊,通過減少無用的大括號,去除語句末尾的分號等視覺雜訊,使得代碼的可讀性顯著提高。閱讀一段良好的Python程序就感覺像是在讀英語一樣,它使你能夠專註於解決問題,而不用太糾結編程語言本身的語法。
豐富強大的庫:Python語言號稱自帶電池(Battery Included),寓意是Python語言的類庫非常的全面,包含了解決各種問題的類庫。無論實現什麼功能,都有現成的類庫可以使用。如果一個功能比較特殊,標準庫沒有提供相應的支持,那麼,很大概率也會有相應的開源項目提供了類似的功能。合理使用Python的類庫和開源項目,能夠快速的實現功能,滿足業務需求。
開發效率高:Python的各個優點是相輔相成的。例如,Python語言因為有了豐富強大的類庫,所以,Python的開發效率能夠顯著提高。相對於 C、C++ 和 Java等編譯語言,Python開發者的效率提高了數倍。實現相同的功能,Python代碼的文件往往只有 C、C++和Java代碼的1/5~1/3。雖然Python語言擁有很多吸引人的特性,但是,各大互聯網公司廣泛使用Python語言,很大程度上是因為Python語言開發效率高這個特點。開發效率高的語言,能夠更好的滿足互聯網快速迭代的需求,因此,Python語言在互聯網公司使用非常廣泛。
應用領域廣泛:Python語言的另一大優點就是應用領域廣泛,工程師可以使用Python 做很多的事情。例如,Web開發、網絡編程、自動化運維、Linux系統管理、數據分析、科學計算、人工智能、機器學習等等。Python語言介於腳本語言和系統語言之間,我們根據需要,既可以將它當做一門腳本語言來編寫腳本,也可以將它當做一個系統語言來編寫服務。
不可忽視的缺點
毫無疑問,Python確實有用很多的優點,每一個優點看起來都非常吸引人。但是,Python並不是沒有缺點的,最主要的缺點有以下幾個:
Python的執行速度不夠快。當然,這也不是一個很嚴重的問題,一般情況下,我們不會拿Python語言與C/C++這樣的語言進行直接比較。在Python語言的執行速度上,一方面,網絡或磁盤的延遲,會抵消掉部分Python本身消耗的時間;另一方面,因為Python 特別容易和C結合起來,因此,我們可以通過分離一部分需要優化速度的應用,將其轉換為編譯好的擴展,並在整個系統中使用Python腳本將這部分應用連接起來,以提高程序的整體效率。
Python的GIL鎖限制並發:Python的另一個大問題是,對多處理器支持不好。如果讀者接觸Python時間比較長,那麼,一定聽說過GIL這個詞。GIL是指Python全局解釋器鎖(Global Interpreter Lock),當Python的默認解釋器要執行字節碼時,都需要先申請這個鎖。這意味着,如果試圖通過多線程擴展應用程序,將總是被這個全局解釋器鎖限制。當然,我們可以使用多進程的架構來提高程序的並發,也可以選擇不同的Python實現來運行我們的程序。
Python 2與Python 3不兼容: 如果一個普通的軟件或者庫,不能夠做到後向兼容,那麼,它會被用戶無情的拋棄了。在Python中,一個槽點是Python 2與Python 3不兼容。因為Python沒有向後兼容,給所有的Python工程師帶來了無數的煩惱。
上述就是總結的Python語言的優缺點。總體來說,Python目前的發展還是非常不錯的。藉著人工智能時代的東風,Python開發人員的未來一定會很光明。
python 什麼是全局解釋器鎖GIL
Python代碼的執行由Python 虛擬機(也叫解釋器主循環,CPython版本)來控制,Python 在設計之初就考慮到要在解釋器的主循環中,同時只有一個線程在執行,即在任意時刻,只有一個線程在解釋器中運行。對Python 虛擬機的訪問由全局解釋器鎖(GIL)來控制,正是這個鎖能保證同一時刻只有一個線程在運行。
在多線程環境中,Python 虛擬機按以下方式執行:
1. 設置GIL
2. 切換到一個線程去運行
3. 運行:
a. 指定數量的字節碼指令,或者
b. 線程主動讓出控制(可以調用time.sleep(0))
4. 把線程設置為睡眠狀態
5. 解鎖GIL
6. 再次重複以上所有步驟
在調用外部代碼(如C/C++擴展函數)的時候,GIL 將會被鎖定,直到這個函數結束為止(由於在這期間沒有Python 的字節碼被運行,所以不會做線程切換)。
Python 的 GIL 是什麼鬼,多線程性能究竟如何
GIL是什麼
首先需要明確的一點是 GIL
並不是Python的特性,它是在實現Python解析器(CPython)時所引入的一個概念。就好比C++是一套語言(語法)標準,但是可以用不同的編譯器來編譯成可執行代碼。有名的編譯器例如GCC,INTEL
C++,Visual
C++等。Python也一樣,同樣一段代碼可以通過CPython,PyPy,Psyco等不同的Python執行環境來執行。像其中的JPython就沒有GIL。然而因為CPython是大部分環境下默認的Python執行環境。所以在很多人的概念里CPython就是Python,也就想當然的把
GIL 歸結為Python語言的缺陷。所以這裡要先明確一點:GIL並不是Python的特性,Python完全可以不依賴於GIL
那麼CPython實現中的GIL又是什麼呢?GIL全稱 Global Interpreter Lock 為了避免誤導,我們還是來看一下官方給出的解釋:
In CPython, the global interpreter lock, or GIL, is a mutex that
prevents multiple native threads from executing Python bytecodes at
once. This lock is necessary mainly because CPython’s memory management
is not thread-safe. (However, since the GIL exists, other features have
grown to depend on the guarantees that it enforces.)
好吧,是不是看上去很糟糕?一個防止多線程並發執行機器碼的一個Mutex,乍一看就是個BUG般存在的全局鎖嘛!別急,我們下面慢慢的分析。
為什麼會有GIL
由於物理上得限制,各CPU廠商在核心頻率上的比賽已經被多核所取代。為了更有效的利用多核處理器的性能,就出現了多線程的編程方式,而隨之帶來的就是線程間數據一致性和狀態同步的困難。 即使在CPU內部的Cache也不例外 ,為了有效解決多份緩存之間的數據同步時各廠商花費了不少心思,也不可避免的帶來了一定的性能損失。
Python當然也逃不開,為了利用多核,Python開始支持多線程。 而解決多線程之間數據完整性和狀態同步的最簡單方法自然就是加鎖。 於是有了GIL這把超級大鎖,而當越來越多的代碼庫開發者接受了這種設定後,他們開始大量依賴這種特性(即默認python內部對象是thread-safe的,無需在實現時考慮額外的內存鎖和同步操作)。
慢慢的這種實現方式被發現是蛋疼且低效的。但當大家試圖去拆分和去除GIL的時候,發現大量庫代碼開發者已經重度依賴GIL而非常難以去除了。有多難?做個類比,像MySQL這樣的“小項目”為了把Buffer
Pool
Mutex這把大鎖拆分成各個小鎖也花了從5.5到5.6再到5.7多個大版為期近5年的時間,本且仍在繼續。MySQL這個背後有公司支持且有固定開發團隊的產品走的如此艱難,那又更何況Python這樣核心開發和代碼貢獻者高度社區化的團隊呢?
所以簡單的說GIL的存在更多的是歷史原因。如果推到重來,多線程的問題依然還是要面對,但是至少會比目前GIL這種方式會更優雅。
GIL的影響
從上文的介紹和官方的定義來看,GIL無疑就是一把全局排他鎖。毫無疑問全局鎖的存在會對多線程的效率有不小影響。甚至就幾乎等於Python是個單線程的程序。那麼讀者就會說了,全局鎖只要釋放的勤快效率也不會差啊。只要在進行耗時的IO操作的時候,能釋放GIL,這樣也還是可以提升運行效率的嘛。或者說再差也不會比單線程的效率差吧。理論上是這樣,而實際上呢?Python比你想的更糟。
下面我們就對比下Python在多線程和單線程下得效率對比。測試方法很簡單,一個循環1億次的計數器函數。一個通過單線程執行兩次,一個多線程執行。最後比較執行總時間。測試環境為雙核的Mac
pro。註:為了減少線程庫本身性能損耗對測試結果帶來的影響,這裡單線程的代碼同樣使用了線程。只是順序的執行兩次,模擬單線程。
順序執行的單線程(single_thread.py)
#! /usr/bin/python
from threading import Thread
import time
def my_counter():
i = 0
for _ in range(100000000):
i = i + 1
return True
def main():
thread_array = {}
start_time = time.time()
for tid in range(2):
t = Thread(target=my_counter)
t.start()
thread_array[tid] = t
for i in range(2):
thread_array[i].join()
end_time = time.time()
print(“Total time: {}”.format(end_time – start_time))
if __name__ == ‘__main__’:
main()
同時執行的兩個並發線程(multi_thread.py)
#! /usr/bin/python
from threading import Thread
import time
def my_counter():
i = 0
for _ in range(100000000):
i = i + 1
return True
def main():
thread_array = {}
start_time = time.time()
for tid in range(2):
t = Thread(target=my_counter)
t.start()
thread_array[tid] = t
for i in range(2):
thread_array[i].join()
end_time = time.time()
print(“Total time: {}”.format(end_time – start_time))
if __name__ == ‘__main__’:
main()
原創文章,作者:EHUHW,如若轉載,請註明出處:https://www.506064.com/zh-hant/n/329982.html