《高性能python》第一章-理解高性能Python-阅读笔记
1.1.1節 計算單元
計算單元的主要屬性是其每個周期能進行的操作數量以及每秒能完成多少個周期。
第一個屬性通過每周期完成的指令數(IPC)①
來衡量,
而第二個屬性則是通過其時
鐘速度衡量。
當新的計算單元被制造出來時,它們的這兩個參數總是互相競爭
矢量計算是指一次提供多個數據給一個 CPU 并能同時被操作。這種類型的 CPU 指
令被稱為 SIMD(單指令多數據)。
超線程技術為主機的操作系統(OS)虛擬了第二個 CPU,而聰明的硬件邏輯則試
圖將兩個指令線程交錯地插入單個 CPU 的執行單元。如果成功插入,能比單線程
提升 30%。一般來講,當兩個線程的工作分布在不同的執行單元上時,這樣做效果
不錯——比如一個操作浮點而另一個操作整數時。
給 CPU 增加更多的核心并不一定能提升程序運行的速度。這是由阿姆達爾定律決
定的。簡單地說,阿姆達爾定律認為如果一個可以運行在多核上的程序有某些執行
路徑必須運行在單核上,那么這些路徑就會成為瓶頸導致最終速度無法通過增加更
多核心來提高。
另外,對于 Python 來說,充分利用多核性能的阻礙主要在于 Python 的全局解釋器
鎖(GIL)。GIL 確保 Python 進程一次只能執行一條指令,無論當前有多少個核心。
這意味著即使某些 Python 代碼可以使用多個核心,在任意時間點僅有一個核心在
執行 Python 的指令。以前面調查的例子來說,即使我們有 100 位提問者,然而一
次僅有一位可以提問和接受回答,并沒有什么用!這看上去是個嚴重的阻礙,特別
是當現在計算機發展的趨勢就是擁有更多而非更快的計算單元的時候。好在這個問
題其實可以通過一些方法來避免,比如標準庫的 multiprocessing,或 numexpr、
Cython 等技術,或分布式計算模型等
1.1.2節 存儲單元
存儲單元的概念包括了主板上的寄存器、RAM 以及硬盤。所有這些不同
類型的存儲單元的主要區別在于其讀寫數據的速度。更復雜的問題在于,其讀寫數
據的速度還與數據的讀寫方式息息相關。
比如,大多數存儲單元一次讀一大塊數據的性能遠好于讀多次小塊數據(順序讀取
VS 隨機數據)。將這些存儲單元中的數據想象成一本書中的書頁,大多數存儲單元
的讀寫速度在連續翻頁時高于經常從一張隨機頁跳至另一張隨機頁。
所有的存儲單元或多或少都受到這一影響,但不同類型存儲單元受到的影響卻大
不相同。
除了讀寫速度以外,存儲單元還有一個延時的屬性,表示了設備為了查找到需要的
數據所花費的時間。一個旋轉硬盤的延時可能較高,因為磁盤必須物理旋轉到一定
速度且讀取磁頭必須移動到正確的位置。而從另一方面來說,RAM 的延時就比較
小,因為一切都是固態的。下面是一個標準工作站內常見的各類存儲單元的簡短描
述,以讀寫速度排序:
旋轉硬盤
計算機關機也能保持的長期存儲。讀寫速度通常較慢,因為磁盤必須物理旋轉
和等待磁頭移動。隨機訪問性能下降但容量很高(TB 級別)。
固態硬盤
類似旋轉硬盤,讀寫速度較快但容量較小(GB 級別)。
RAM
用于保存應用程序的代碼和數據(比如用到的各種變量)。具有更快的讀寫速
度且在隨機訪問時性能良好,但通常受限于容量(GB 級別)。
L1/L2 緩存
極快的讀寫速度。進入 CPU 的數據必須經過這里。很小的容量(KB 級別)。
圖 1-2 展示了當今市面上可以見到的這幾類存儲單元的區別。
一個清晰可見的趨勢是讀寫速度和容量成反比—當我們試圖加快速度時,容量就
下降了。因此,很多系統都實現了一個分層的存儲:數據一開始都在硬盤里,部分
進入 RAM,然后很小的一個子集進入 L1/L2 緩存。這種分層使得程序可以根據訪
問速度的需求將數據保存在不同的地方。在試圖優化程序的存儲訪問模式時,我們
只是簡單優化了數據存放的位置、布局(為了增加順序讀取的次數),以及數據在
不同位置之間移動的次數。另外,異步 I/O 和緩存預取等技術還提供了很多方法來
確保數據在被需要時就已經存在于對應的地方而不需要浪費額外的計算時間—
這些過程可以在進行其他計算時獨立進行!
1.1.3 通信層
最后,讓我們看看這些基本單元如何互相通信。通信有很多模式,但它們都是同一
樣東西的變種:總線。
比如說,前端總線是 RAM 和 L1/L2 緩存之間的連接。它將已經準備好被處理器操
作的數據移入一個集結場所以備計算所需,又將計算結果移出。除此之外還有其他
總線,如外部總線就是硬件設備(如硬盤和網卡)通向 CPU 和系統內存的主干線。
該總線通常比前端總線慢。
事實上,L1/L2 緩存的很多好處實際上是來自更快的總線。因為可以將需要計算的
數據在慢速總線(連接 RAM 和緩存)上攢成大的數據塊,然后以非常快的速度從
后端總線(連接緩存和 CPU)傳入 CPU,這樣 CPU 就可以進行更多計算而無須等
待這么長的時間。
同樣,使用 GPU 的不利之處很多都來自它所連接的總線:因為 GPU 通常是一個外
部設備,它通過 PCI 總線通信,速度遠遠慢于前端總線。結果,GPU 數據的輸入
輸出就像是一種抽稅操作。異質架構,一種在前端總線上同時具有 CPU 和 GPU 的
計算機架構的興起就是為了降低數據傳輸成本,使得 GPU 能夠被使用在需要傳輸
大量數據的計算上。
除了計算機內部的通信模塊,網絡可以被認為是另一種通信模塊。不過這個模塊就
比之前討論的更為靈活,一個網絡設備可以直接連接至一個存儲設備,如網絡連接
存儲(NAS)設備或計算機集群中的另一臺計算機節點。但是網絡通信通常要比之
前討論的其他類型的通信慢很多。前端總線每秒可以傳輸數十 GB,而網絡則僅有
數十 MB。
現在我們清楚,一條總線的主要屬性是它的速度:在給定時間內它能傳輸多少數據。
該屬性由兩個因素決定:
一次能傳輸多少數據(總線帶寬)和每秒能傳輸幾次(總線頻率)。
需要說明的是一次傳輸的數據總是有序的:一塊數據先從內存中讀出,然后被移動到另一個地方。這就是為什么總線的速度可以被拆分為兩個因素,因為這兩個因素分別獨立影響計算的不同方面:
高的總線帶寬可以一次性移動所有相關
數據,有助于矢量化的代碼(或任何順序讀取內存的代碼),而另一方面,低帶寬
高頻率有助于那些經常隨機讀取內存的代碼。
有意思的是,這些屬性是由計算機設計者在主板的物理布局上決定的:當芯片之間相距較近時,它們之間的物理鏈路就
較短,就可以允許更高的傳輸速度。而物理鏈路的數量則決定了總線的帶寬(帶寬這個詞真的具有物理上的意義!)。
下面是文中的小標注
①不要跟進程間通信(也是 IPC)混淆——我們會在第 9 章討論這個主題。
總結
以上是生活随笔為你收集整理的《高性能python》第一章-理解高性能Python-阅读笔记的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 适合创业者的网名,创业名字霸气十足552
- 下一篇: Python计算防蓝光眼镜加权阻隔率