Go 語言之三駕馬車 - 騰訊雲社區

來源:互聯網
上載者:User
這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。

導語:Go語言的三個核心設計: interface 、goroutine 、 channel

less is more —— Wikipedia

interface

Go是一門面向介面編程的語言,interface的設計自然是重中之重。Go中對於interface設計的巧妙之處就在於空的interface可以被當作“Duck”類型使用,它使得Go這樣的靜態語言擁有了一定的動態性,卻又不損失靜態語言在型別安全方面擁有的編譯時間檢查的優勢。

source code

從底層實現來看,interface實際上是一個結構體,包含兩個成員。其中一個成員指標指向了包含類型資訊的地區,可以理解為虛表指標,而另一個則指向具體資料,也就是該interface實際引用的資料。

其中 interfacetype 包含了一些關於interface本身的資訊,_type表示具體實作類別型,在下文eface中會有詳細描述,bad 是一個狀態變數,fun是一個長度為1的指標數組,在 fun[0] 的地址後面依次儲存method對應的函數指標。go runtime 包裡面有一個hash表,通過這個hash表可以取得 itab,link跟inhash則是為了儲存hash表中對應的位置並設定標識。主要代碼如下:

Itab的結構如下:

其中 interfacetype 包含了一些關於interface本身的資訊,_type表示具體實作類別型,在下文eface中會有詳細描述,bad 是一個狀態變數,fun是一個長度為1的指標數組,在 fun[0] 的地址後面依次儲存method對應的函數指標。go runtime 包裡面有一個hash表,通過這個hash表可以取得 itab,link跟inhash則是為了儲存hash表中對應的位置並設定標識。主要代碼如下:

空介面的實現略有不同。Go中任何對象都可以表示為interface{},類似於C中的 void*,而且interface{}中存有類型資訊。

Type的結構如下:

i_example

關於interface的應用,下面舉個簡單的例子,是關於Go與Mysql資料庫互動的。

首先在mysql test庫中建立一張任務資訊表:

資料庫互動最基本的四個操作:增刪改查, 這裡以查詢為例:

Go來實現查詢這張表裡面的所有資料

其中:

這段代碼可以實現查表這個簡單的邏輯,但是有一個小小的問題就是,我們這張表結構比較簡單只有4個欄位,如果換一張有20+個欄位甚至更多的表來查詢的話,這段代碼就顯得太過於低效,這個時候我們便可以引入interface{}來進行最佳化。
最佳化後的代碼如下:

由於interface{}可以儲存任何類型的資料,所以通過構造args、values兩個數組,其中args的每個值指向values相應值的地址,來對資料進行批量的讀取及後續操作,值得注意的是Go是一門強型別的語言,而且不同的interface{}是存有不同的類型資訊的,在進行賦值等相關操作時需要進行類型轉換。

Go對於Mysql交易處理也提供了比較好的支援。一般的操作使用的是db對象的方法,事務則是使用sql.Tx對象。使用db的Begin方法可以建立tx對象。tx對象也有資料庫互動的Query,Exec和Prepare方法,與db的操作類似。查詢或修改的操作完畢之後,需要調用tx對象的Commit()提交或者Rollback()復原。

例如,現在需要利用事務對之前建立的user表進行update操作,代碼如下

注意: “ := “ 跟 “ = “兩個操作符不要弄混淆

如果不需要進行交易處理的話,update對應的代碼如下:

可以與上面增加事務操作的代碼進行對比,因為操作比較簡單所以也就增加了幾行代碼,以及將db對象換成了tx對象。

goroutine

並發:同一時間內處理(dealing with)不同的事情
並行:同一時間內做(doing)不同的事情

Go從語言層面就支援了並行,而goroutine則是Go並行設計的核心。本質上,goroutine就是協程,擁有獨立的可以自行管理的調用棧,可以把goroutine理解為輕量級的thread。但是thread是作業系統調度的,搶佔式的。goroutine是通過自己的調度器來調度的。

scheduler

Go的調度器實現了G-P-M調度模型,其中有三個重要的結構:M,P,G

M : Machine (OS thread)
P : Context (Go Scheduler)
G : Goroutine

底層的資料結構長這樣:

M、P 和 G 之間的互動可以通過下面這幾張來自go runtime scheduler的圖來展現

中看,有2個物理線程M,每一個M都擁有一個上下文P,也都有一個正在啟動並執行goroutine G。圖中灰色的那些G並沒有運行,而是出於ready的就緒態,正在等待被調度。由P來維護著這個runqueue隊列。

圖中的M1可能是被建立出來的,也可能是從線程緩衝中取出來的。當M0返回時,它必須嘗試擷取P來運行G,通常情況下,它會嘗試從其他的thread那裡”steal”一個P過來,失敗的話,它就把G放在一個global runqueue裡,然後自己會被放入線程緩衝裡。所有的P會周期性的檢查global runqueue,否則global runqueue上的G永遠無法執行。

另一種情況是P所分配的任務G很快就執行完了(因為分配不均),這就導致了某些P處於空閑狀態而系統卻依然在運行態。但如果global runqueue沒有任務G了,那麼P就不得不從其他的P那裡拿一些G來執行。通常情況下,如果P從其他的P那裡要偷一個任務的話,一般就‘steal’ runqueue的一半,這就確保了每個thread都能充分的使用。

P如何從其他P維護的隊列中”steal”到G呢?這就涉及到work-stealing演算法,關於該演算法的更多資訊可以參考這篇文章。

g_example

舉個簡單的例子來示範下goroutine是如何啟動並執行

這段代碼非常簡單,兩個不同的goroutine非同步運行

運行結果如下:

然後做個小小的改動,只是將main()中的兩個函數的位置互換,其餘代碼變:

會出現一件有意思的事情:

原因也很簡單,因為main()返回時, 並不會等待其他goroutine(非主goroutine)結束。對上面的例子, 主函數執行完第一個say()後,建立了一個新的goroutine沒來得及執行程式就結束了,所以會出現上面的運行結果。

channel

goroutine在相同的地址空間中運行,因此必須同步對共用記憶體的訪問。Go語言提供了一個很好的通訊機制channel,來滿足goroutine之間資料的通訊。channel與Unix shell 中的雙向管道有些類似:可以通過它發送或者接收值。

source code

其中waitq的結構如下

可以看到channel其實就是一個隊列加一個鎖。其中sendx和recvx可以看做生產者跟消費者隊列,分別儲存的是等待在channel上進行讀操作的goroutine和等待在channel上進行寫操作的goroutine,如所示。

寫channel (ch <- x)的具體實現如下(只選取了核心代碼):

具體可以分為三種情況:

  • 有goroutine阻塞在channel上,而且chanbuf為空白,直接將資料發送給該goroutine上。
  • chanbuf有空間可用:將資料放到chanbuf裡面。
  • chanbuf沒有空間可用:阻塞當前goroutine。



讀channel( <-ch)和發送的操作類似,就不帖代碼展示了。

c_example

關於goroutine跟channel進行通訊的一個簡單的例子,邏輯很簡單:

這裡我們定義了兩個帶緩衝的channel jobs 和 results,如果把這兩個channel都換成不帶緩衝的,就會報錯,不過可以這樣進行處理就可以了:

比較常見的channel操作還有select , 存在多個channel的時候,可以通過select可以監聽channel上的資料流動。

因為 ch1 和 ch2 都為空白,所以 case1 和 case2 都不會讀取成功。 則 select 執行 default 語句。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.