golang數據分析,golang數據分析框架

本文目錄一覽:

(十一)golang 內存分析

編寫過C語言程序的肯定知道通過malloc()方法動態申請內存,其中內存分配器使用的是glibc提供的ptmalloc2。 除了glibc,業界比較出名的內存分配器有Google的tcmalloc和Facebook的jemalloc。二者在避免內存碎片和性能上均比glic有比較大的優勢,在多線程環境中效果更明顯。

Golang中也實現了內存分配器,原理與tcmalloc類似,簡單的說就是維護一塊大的全局內存,每個線程(Golang中為P)維護一塊小的私有內存,私有內存不足再從全局申請。另外,內存分配與GC(垃圾回收)關係密切,所以了解GC前有必要了解內存分配的原理。

為了方便自主管理內存,做法便是先向系統申請一塊內存,然後將內存切割成小塊,通過一定的內存分配算法管理內存。 以64位系統為例,Golang程序啟動時會向系統申請的內存如下圖所示:

預申請的內存劃分為spans、bitmap、arena三部分。其中arena即為所謂的堆區,應用中需要的內存從這裡分配。其中spans和bitmap是為了管理arena區而存在的。

arena的大小為512G,為了方便管理把arena區域劃分成一個個的page,每個page為8KB,一共有512GB/8KB個頁;

spans區域存放span的指針,每個指針對應一個page,所以span區域的大小為(512GB/8KB)乘以指針大小8byte = 512M

bitmap區域大小也是通過arena計算出來,不過主要用於GC。

span是用於管理arena頁的關鍵數據結構,每個span中包含1個或多個連續頁,為了滿足小對象分配,span中的一頁會劃分更小的粒度,而對於大對象比如超過頁大小,則通過多頁實現。

根據對象大小,劃分了一系列class,每個class都代表一個固定大小的對象,以及每個span的大小。如下表所示:

上表中每列含義如下:

class: class ID,每個span結構中都有一個class ID, 表示該span可處理的對象類型

bytes/obj:該class代表對象的字節數

bytes/span:每個span佔用堆的字節數,也即頁數乘以頁大小

objects: 每個span可分配的對象個數,也即(bytes/spans)/(bytes/obj)waste

bytes: 每個span產生的內存碎片,也即(bytes/spans)%(bytes/obj)上表可見最大的對象是32K大小,超過32K大小的由特殊的class表示,該class ID為0,每個class只包含一個對象。

span是內存管理的基本單位,每個span用於管理特定的class對象, 跟據對象大小,span將一個或多個頁拆分成多個塊進行管理。src/runtime/mheap.go:mspan定義了其數據結構:

以class 10為例,span和管理的內存如下圖所示:

spanclass為10,參照class表可得出npages=1,nelems=56,elemsize為144。其中startAddr是在span初始化時就指定了某個頁的地址。allocBits指向一個位圖,每位代表一個塊是否被分配,本例中有兩個塊已經被分配,其allocCount也為2。next和prev用於將多個span鏈接起來,這有利於管理多個span,接下來會進行說明。

有了管理內存的基本單位span,還要有個數據結構來管理span,這個數據結構叫mcentral,各線程需要內存時從mcentral管理的span中申請內存,為了避免多線程申請內存時不斷的加鎖,Golang為每個線程分配了span的緩存,這個緩存即是cache。src/runtime/mcache.go:mcache定義了cache的數據結構

alloc為mspan的指針數組,數組大小為class總數的2倍。數組中每個元素代表了一種class類型的span列表,每種class類型都有兩組span列表,第一組列表中所表示的對象中包含了指針,第二組列表中所表示的對象不含有指針,這麼做是為了提高GC掃描性能,對於不包含指針的span列表,沒必要去掃描。根據對象是否包含指針,將對象分為noscan和scan兩類,其中noscan代表沒有指針,而scan則代表有指針,需要GC進行掃描。mcache和span的對應關係如下圖所示:

mchache在初始化時是沒有任何span的,在使用過程中會動態的從central中獲取並緩存下來,跟據使用情況,每種class的span個數也不相同。上圖所示,class 0的span數比class1的要多,說明本線程中分配的小對象要多一些。

cache作為線程的私有資源為單個線程服務,而central則是全局資源,為多個線程服務,當某個線程內存不足時會向central申請,當某個線程釋放內存時又會回收進central。src/runtime/mcentral.go:mcentral定義了central數據結構:

lock: 線程間互斥鎖,防止多線程讀寫衝突

spanclass : 每個mcentral管理着一組有相同class的span列表

nonempty: 指還有內存可用的span列表

empty: 指沒有內存可用的span列表

nmalloc: 指累計分配的對象個數線程從central獲取span步驟如下:

將span歸還步驟如下:

從mcentral數據結構可見,每個mcentral對象只管理特定的class規格的span。事實上每種class都會對應一個mcentral,這個mcentral的集合存放於mheap數據結構中。src/runtime/mheap.go:mheap定義了heap的數據結構:

lock: 互斥鎖

spans: 指向spans區域,用於映射span和page的關係

bitmap:bitmap的起始地址

arena_start: arena區域首地址

arena_used: 當前arena已使用區域的最大地址

central: 每種class對應的兩個mcentral

從數據結構可見,mheap管理着全部的內存,事實上Golang就是通過一個mheap類型的全局變量進行內存管理的。mheap內存管理示意圖如下:

系統預分配的內存分為spans、bitmap、arean三個區域,通過mheap管理起來。接下來看內存分配過程。

針對待分配對象的大小不同有不同的分配邏輯:

(0, 16B) 且不包含指針的對象: Tiny分配

(0, 16B) 包含指針的對象:正常分配

[16B, 32KB] : 正常分配

(32KB, -) : 大對象分配其中Tiny分配和大對象分配都屬於內存管理的優化範疇,這裡暫時僅關注一般的分配方法。

以申請size為n的內存為例,分配步驟如下:

Golang內存分配是個相當複雜的過程,其中還摻雜了GC的處理,這裡僅僅對其關鍵數據結構進行了說明,了解其原理而又不至於深陷實現細節。1、Golang程序啟動時申請一大塊內存並劃分成spans、bitmap、arena區域

2、arena區域按頁劃分成一個個小塊。

3、span管理一個或多個頁。

4、mcentral管理多個span供線程申請使用

5、mcache作為線程私有資源,資源來源於mcentral。

六星教育:Python和go語言都很火,我要怎麼選?

python和go語言有區別:1、Python語法使用縮進來指示代碼塊;Go語法基於打開和關閉括號;2、Python是基於面向對象編程的多範式語言;Go是基於並發編程範式的過程編程語言。3、Python是動態類型語言,Go是靜態類型語言。

Go語言(又稱 Golang)是 Google 的 Robert Griesemer,Rob Pike 及 Ken Thompson 開發的一種靜態強類型、編譯型語言。Go 語言語法與 C 相近,但功能上有:內存安全,GC(垃圾回收),結構形態以及 CSP-style 並發計算。

python是一種廣泛使用的具有動態語義的解釋型,面向對象的高級編程語言。

Python是一種面向對象的高級編程語言,具有集成的動態語義,主要用於Web和應用程序開發。它在快速應用程序開發領域極具吸引力,因為它提供動態類型和動態綁定選項。

Python是一種解釋型語言,這意味着用Python編寫的程序不需要事先編譯就可以運行,從而可以輕鬆地測試小段代碼並使用Python編寫的代碼更容易在平台之間移動。

python和go語言的區別:

1、語法

Python的語法使用縮進來指示代碼塊。Go的語法基於打開和關閉括號。

2、範例

Python是一種基於面向對象編程的多範式,命令式和函數式編程語言。它堅持這樣一種觀點,即如果一種語言在某些情境中表現出某種特定的方式,理想情況下它應該在所有情境中都有相似的作用。但是,它又不是純粹的OOP語言,它不支持強封裝,這是OOP的主要原則之一。

Go是一種基於並發編程範式的過程編程語言,它與C具有表面相似性。實際上,Go更像是C的更新版本。

3、並發

Python沒有提供內置的並發機制,而Go有內置的並發機制。

4、類型化

Python是動態類型語言,而Go是一種靜態類型語言,它實際上有助於在編譯時捕獲錯誤,這可以進一步減少生產後期的嚴重錯誤。

5、安全性

Python是一種強類型語言,它是經過編譯的,因此增加了一層安全性。Go具有分配給每個變量的類型,因此,它提供了安全性。但是,如果發生任何錯誤,用戶需要自己運行整個代碼。

6、管理內存

Go允許程序員在很大程度上管理內存。而,Python中的內存管理完全自動化並由Python VM管理;它不允許程序員對內存管理負責。

7、庫

與Go相比,Python提供的庫數量要大得多。然而,Go仍然是新的,並且還沒有取得很大進展。

8、速度:

Go的速度遠遠超過Python。

Python與Golang對比:

1、特點:

Golang

①靜態強類型、編譯型、並髮型

靜態類型語言,但是有動態語言的感覺。(靜態類型的語言就是可以在編譯的時候檢查出來隱藏的大多數問題,動態語言的感覺就是有很多的包可以使用,寫起來的效率很高)

可直接編譯成機器碼,不依賴其他庫,glibc的版本有一定要求,部署就是扔一個文件上去就完成了。

語言層面支持並發,這個就是Go最大的特色,天生的支持並發。Go就是基因裡面支持的並發,可以充分地利用多核,很容易地使用並發。

②垃圾回收機制

內置runtime,支持垃圾回收,這屬於動態語言的特性之一吧,雖然目前來說GC(內存垃圾回收機制)不算完美,但是足以應付我們所能遇到的大多數情況,特別是Go1.1之後的GC。

③支持面向對象編程

有接口類型和實現類型的概念,但是用嵌入替代了繼承。

④豐富的標準庫

Go目前已經內置了大量的庫,特別是網絡庫非常強大。

⑤內嵌C支持

Go裡面也可以直接包含C代碼,利用現有的豐富的C庫

Python

①解釋型語言

程序不需要在運行前編譯,在運行程序的時候才翻譯,專門的解釋器負責在每個語句執行的時候解釋程序代碼。這樣解釋型語言每執行一次就要翻譯一次,效率比較低。

②動態數據類型 

支持重載運算符,也支持泛型設計。(運算符重載,就是對已有的運算符重新進行定義,賦予其另一種功能,以適應不同的數據類型。泛型設計就是定義的時候不需要指定類型,在客戶端使用的時候再去指定類型)

③完全面向對象的語言

函數,模塊,數字,字符串都是對象,在Python中,一切接對象

完全支持繼承,重載,多重繼承 

④擁有強大的標準庫

Python語言的核心只包含數字,字符串,列表,元祖,字典,集合,文件等常見類型和函數,而由Python標準庫提供了系統管理,網絡通信,文本處理,數據庫接口,圖形系統,XML處理等額外的功能。

⑤社區提供了大量第三方庫

Python 社區提供了大量的第三方模塊,使用方式與標準庫類似。它們的功能覆蓋 科學計算、人工智能、機器學習、Web 開發、數據庫接口、圖形系統 多個領域。

2、應用

Python

①網絡編程

web應用,網絡爬蟲

②數據分析和機器學習

③自動化測試

④自動化運維

Golang

①服務器編程

處理日誌、數據打包、虛擬機處理、文件系統等。

②分布式系統,數據庫代理器等

③網絡編程

這一塊目前應用最廣,包括Web應用、API應用、下載應用。

④內存數據庫

如google開發的groupcache,couchbase的部分組件。

⑥雲平台

Go語言和Python學哪個好?

Python 可以很好地集成到企業級應用中,可用於機器語言和 AI 應用。Go 語言的特點表明它具備輕量級線程實現(Goroutine)、智能標準庫、強大的內置安全性,且可使用最簡語法進行編程。Go 在大部分案例中領先,被認為是 Python 的有效替代方案。開發者在選擇編程語言時,應考慮開發項目的性質和規模,以及所需的技能組合。

放下個人偏見和喜好,從優點和功能的角度來評價兩種語言。不管選擇了哪種語言,Go 和 Python 都在持續演進。儘管在大多數情況下 Golang 可能是更好的選擇,但Python語言也是不斷更新迭代的。以上就是本次分享的全部內容,如果你也想學習一門編程語言,可以考慮下 六星教育 ,這裡的課程體系,師資團隊以及售後服務,一定不會讓你失望!

Golang database/sql源碼分析

Gorm是Go語言開發用的比較多的一個ORM。它的功能比較全:

但是這篇文章中並不會直接看Gorm的源碼,我們會先從database/sql分析。原因是Gorm也是基於這個包來封裝的一些功能。所以只有先了解了database/sql包才能更加好的理解Gorm源碼。

database/sql 其實也是一個對於mysql驅動的上層封裝。”github.com/go-sql-driver/mysql”就是一個對於mysql的驅動,database/sql 就是在這個基礎上做的基本封裝包含連接池的使用

下面這個是最基本的增刪改查操作

操作分下面幾個步驟:

因為Gorm的連接池就是使用database/sql包中的連接池,所以這裡我們需要學習一下包里的連接池的源碼實現。其實所有連接池最重要的就是連接池對象、獲取函數、釋放函數下面來看一下database/sql中的連接池。

DB對象

獲取方法

釋放連接方法

連接池的實現有很多方法,在database/sql包中使用的是chan阻塞 使用map記錄等待列表,等到有連接釋放的時候再把連接傳入等待列表中的chan 不在阻塞返回連接。

之前我們看到的Redigo是使用一個chan 來阻塞,然後釋放的時候放入空閑列表,在往這一個chan中傳入struct{}{},讓程序繼續 獲取的時候再從空閑列表中獲取。並且使用的是鏈表的結構來存儲空閑列表。

database/sql 是對於mysql驅動的封裝,然而Gorm則是對於database/sql的再次封裝。讓我們可以更加簡單的實現對於mysql數據庫的操作。

golang map源碼淺析

golang 中 map的實現結構為: 哈希表 + 鏈表。 其中鏈表,作用是當發生hash衝突時,拉鏈法生成的結點。

可以看到, []bmap 是一個hash table, 每一個 bmap是我們常說的“桶”。 經過hash 函數計算出來相同的hash值, 放到相同的桶中。 一個 bmap中可以存放 8個 元素, 如果多出8個,則生成新的結點,尾接到隊尾。

以上是只是靜態文件 src/runtime/map.go 中的定義。 實際上編譯期間會給它加料 ,動態地創建一個新的結構:

上圖就是 bmap的內存模型, HOB Hash 指的就是 top hash。 注意到 key 和 value 是各自放在一起的,並不是 key/value/key/value/… 這樣的形式。源碼里說明這樣的好處是在某些情況下可以省略掉 padding 字段,節省內存空間。

每個 bmap設計成 最多只能放 8 個 key-value 對 ,如果有第 9 個 key-value 落入當前的 bmap,那就需要再構建一個 bmap,通過 overflow 指針連接起來。

map創建方法:

我們實際上是通過調用的 makemap ,來創建map的。實際工作只是初始化了hmap中的各種字段,如:設置B的大小, 設置hash 種子 hash 0.

注意 :

makemap 返回是*hmap 指針, 即 map 是引用對象, 對map的操作會影響到結構體內部 。

使用方式

對應的是下面兩種方法

map的key的類型,實現了自己的hash 方式。每種類型實現hash函數方式不一樣。

key 經過哈希計算後得到hash值,共 64 個 bit 位。 其中後B 個bit位置, 用來定位當前元素落在哪一個桶里, 高8個bit 為當前 hash 值的top hash。 實際上定位key的過程是一個雙重循環的過程, 外層循環遍歷 所有的overflow, 內層循環遍歷 當前bmap 中的 8個元素 。

舉例說明: 如果當前 B 的值為 5, 那麼buckets 的長度 為 2^5 = 32。假設有個key 經過hash函數計算後,得到的hash結果為:

外層遍歷bucket 中的鏈表

內層循環遍歷 bmap中的8個 cell

建議先不看此部分內容,看完後續 修改 map中元素 – 擴容 操作後 再回頭看此部分內容。

擴容前的數據:

等量擴容後的數據:

等量擴容後,查找方式和原本相同, 不多做贅述。

兩倍擴容後的數據

兩倍擴容後,oldbuckets 的元素,可能被分配成了兩部分。查找順序如下:

此處只分析 mapaccess1 ,。 mapaccess2 相比 mapaccess1 多添加了是否找到的bool值, 有興趣可自行看一下。

使用方式:

步驟如下:

擴容條件 :

擴容的標識 : h.oldbuckets != nil

假設當前定位到了新的buckets的3號桶中,首先會判斷oldbuckets中的對應的桶有沒有被搬遷過。 如果搬遷過了,不需要看原來的桶了,直接遍歷新的buckets的3號桶。

擴容前:

等量擴容結果

雙倍擴容會將old buckets上的元素分配到x, y兩個部key 1 B == 0 分配到x部分,key 1 B == 1 分配到y部分

注意: 當前只對雙倍擴容描述, 等量擴容只是重新填充了一下元素, 相對位置沒有改變。

假設當前map 的B == 5,原本元素經過hash函數計算的 hash 值為:

因為雙倍擴容之後 B = B + 1,此時B == 6。key 1 B == 1, 即 當前元素rehash到高位,新buckets中 y 部分. 否則 key 1 B == 0 則rehash到低位,即x 部分。

使用方式:

可以看到,每一遍歷生成迭代器的時候,會隨機選取一個bucket 以及 一個cell開始。 從前往後遍歷,再次遍歷到起始位置時,遍歷完成。

原創文章,作者:UJLDH,如若轉載,請註明出處:https://www.506064.com/zh-hant/n/128111.html

(0)
打賞 微信掃一掃 微信掃一掃 支付寶掃一掃 支付寶掃一掃
UJLDH的頭像UJLDH
上一篇 2024-10-03 23:24
下一篇 2024-10-03 23:24

相關推薦

  • Python讀取CSV數據畫散點圖

    本文將從以下方面詳細闡述Python讀取CSV文件並畫出散點圖的方法: 一、CSV文件介紹 CSV(Comma-Separated Values)即逗號分隔值,是一種存儲表格數據的…

    編程 2025-04-29
  • Ojlat:一款快速開發Web應用程序的框架

    Ojlat是一款用於快速開發Web應用程序的框架。它的主要特點是高效、易用、可擴展且功能齊全。通過Ojlat,開發人員可以輕鬆地構建出高質量的Web應用程序。本文將從多個方面對Oj…

    編程 2025-04-29
  • Zlios——一個多功能的開發框架

    你是否在開發過程中常常遇到同樣的問題,需要不斷去尋找解決方案?你是否想要一個多功能、易於使用的開發框架來解決這些問題?那麼,Zlios就是你需要的框架。 一、簡介 Zlios是一個…

    編程 2025-04-29
  • Python中讀入csv文件數據的方法用法介紹

    csv是一種常見的數據格式,通常用於存儲小型數據集。Python作為一種廣泛流行的編程語言,內置了許多操作csv文件的庫。本文將從多個方面詳細介紹Python讀入csv文件的方法。…

    編程 2025-04-29
  • 如何用Python統計列表中各數據的方差和標準差

    本文將從多個方面闡述如何使用Python統計列表中各數據的方差和標準差, 並給出詳細的代碼示例。 一、什麼是方差和標準差 方差是衡量數據變異程度的統計指標,它是每個數據值和該數據值…

    編程 2025-04-29
  • Python多線程讀取數據

    本文將詳細介紹多線程讀取數據在Python中的實現方法以及相關知識點。 一、線程和多線程 線程是操作系統調度的最小單位。單線程程序只有一個線程,按照程序從上到下的順序逐行執行。而多…

    編程 2025-04-29
  • 使用Golang調用Python

    在現代軟件開發中,多種編程語言的協作是相當普遍的。其中一種使用場景是Golang調用Python,這使得在使用Python庫的同時,可以利用Golang的高性能和強大並發能力。這篇…

    編程 2025-04-29
  • agavi開發框架

    Agavi是一個基於MVC模式的Web應用程序開發框架,以REST和面向資源的設計為核心思想。本文章將從Agavi的概念、優點、使用方法和實例等方面進行詳細介紹。 一、概念 Aga…

    編程 2025-04-29
  • Python兩張表數據匹配

    本篇文章將詳細闡述如何使用Python將兩張表格中的數據匹配。以下是具體的解決方法。 一、數據匹配的概念 在生活和工作中,我們常常需要對多組數據進行比對和匹配。在數據量較小的情況下…

    編程 2025-04-29
  • Python爬取公交數據

    本文將從以下幾個方面詳細闡述python爬取公交數據的方法: 一、準備工作 1、安裝相關庫 import requests from bs4 import BeautifulSou…

    編程 2025-04-29

發表回復

登錄後才能評論