本文目錄一覽:
- 1、go語言無緩衝的channel
- 2、golang調用so庫同步函數停止
- 3、Go語言WaitGroup使用時需要注意什麼
- 4、Golang 語言深入理解:channel
- 5、golangaddint64作用
go語言無緩衝的channel
無緩衝的通道(unbuffered channel)是指在接收前沒有能力保存任何值的通道。
這種類型的通道要求發送goroutine和接收goroutine同時準備好,才能完成發送和接收操作。否則,通道會導致先執行發送或接收操作的 goroutine 阻塞等待。
這種對通道進行發送和接收的交互行為本身就是同步的。其中任意一個操作都無法離開另一個操作單獨存在。
阻塞:由於某種原因數據沒有到達,當前協程(線程)持續處於等待狀態,直到條件滿足,才接觸阻塞。
同步:在兩個或多個協程(線程)間,保持數據內容一致性的機制。
下圖展示兩個 goroutine 如何利用無緩衝的通道來共享一個值:
在第 1 步,兩個 goroutine 都到達通道,但哪個都沒有開始執行發送或者接收。
在第 2 步,左側的 goroutine 將它的手伸進了通道,這模擬了向通道發送數據的行為。這時,這個 goroutine 會在通道中被鎖住,直到交換完成。
在第 3 步,右側的 goroutine 將它的手放入通道,這模擬了從通道里接收數據。這個 goroutine 一樣也會在通道中被鎖住,直到交換完成。
在第 4 步和第 5 步,進行交換,並最終,在第 6 步,兩個 goroutine 都將它們的手從通道里拿出來,這模擬了被鎖住的 goroutine 得到釋放。兩個 goroutine 現在都可以去做別的事情了。
如果沒有指定緩衝區容量,那麼該通道就是同步的,因此會阻塞到發送者準備好發送和接收者準備好接收。
無緩衝channel: —— 同步通信
golang調用so庫同步函數停止
測試動態庫步驟:
1、test_so.h
2、test_so.c
3、生成so
4、複製so文件到Go項目目錄
Go項目目錄
1、load_so.h
2、load_so.c
3、test.go
4、Go項目目錄要放在$GOPATH/src/目錄下,這也是正常操作。
test目錄為Go項目,裡邊是上述創建的所有源碼文件。
在$GOPATH/src/test/里直接使用gobuild編譯生成test二進制文件,此處需要注意執行路徑。
問題
1、/**/注釋的代碼下一行一定是import“C”,中間不能有空行
2、importC必須單獨一行,不能和其它庫一起導入
3、有人編譯的時候會報錯:
這個主要是執行目錄問題,一定要在$GOPATH/src/項目/目錄下,用gobuild執行,gobuild後邊不要有任何文件名。
或者用gorun.運行,或者goruntest,test是項目名。不能用goruntest.go。
4、還有人報這個錯:test.go文件里的cgoLDFLAGS:-ldl這一行不要刪掉。
Go語言WaitGroup使用時需要注意什麼
WaitGroup在go語言中,用於線程同步,單從字面意思理解,wait等待的意思,group組、團隊的意思,WaitGroup就是指等待一組,等待一個系列執行完成後才會繼續向下執行。Golang 中的 WaitGroup 一直是同步 goroutine 的推薦實踐。自己用了兩年多也沒遇到過什麼問題。
直到最近的一天同事扔過來一段奇怪的代碼:
好了,到這裡終於解決了,以上就是關於Go語言WaitGroup使用時需要注意的一些坑,希望本文中提到的這些問題對大家學習或者使用Go語言的時候能有所幫助,如果有疑問大家可以留言交流。
Golang 語言深入理解:channel
本文是對 Gopher 2017 中一個非常好的 Talk�: [Understanding Channel](GopherCon 2017: Kavya Joshi – Understanding Channels) 的學習筆記,希望能夠通過對 channel 的關鍵特性的理解,進一步掌握其用法細節以及 Golang 語言設計哲學的管窺蠡測。
channel 是可以讓一個 goroutine 發送特定值到另一個 gouroutine 的通信機制。
原生的 channel 是沒有緩存的(unbuffered channel),可以用於 goroutine 之間實現同步。
關閉後不能再寫入,可以讀取直到 channel 中再沒有數據,並返回元素類型的零值。
gopl/ch3/netcat3
首先從 channel 是怎麼被創建的開始:
在 heap 上分配一個 hchan 類型的對象,並將其初始化,然後返回一個指向這個 hchan 對象的指針。
理解了 channel 的數據結構實現,現在轉到 channel 的兩個最基本方法: sends 和 receivces ,看一下以上的特性是如何體現在 sends 和 receives 中的:
假設發送方先啟動,執行 ch – task0 :
如此為 channel 帶來了 goroutine-safe 的特性。
在這樣的模型里, sender goroutine – channel – receiver goroutine 之間, hchan 是唯一的共享內存,而這個唯一的共享內存又通過 mutex 來確保 goroutine-safe ,所有在隊列中的內容都只是副本。
這便是著名的 golang 並發原則的體現:
發送方 goroutine 會阻塞,暫停,並在收到 receive 後才恢復。
goroutine 是一種 用戶態線程 , 由 Go runtime 創建並管理,而不是操作系統,比起操作系統線程來說,goroutine更加輕量。
Go runtime scheduler 負責將 goroutine 調度到操作系統線程上。
runtime scheduler 怎麼將 goroutine 調度到操作系統線程上?
當阻塞發生時,一次 goroutine 上下文切換的全過程:
然而,被阻塞的 goroutine 怎麼恢復過來?
阻塞發生時,調用 runtime sheduler 執行 gopark 之前,G1 會創建一個 sudog ,並將它存放在 hchan 的 sendq 中。 sudog 中便記錄了即將被阻塞的 goroutine G1 ,以及它要發送的數據元素 task4 等等。
接收方 將通過這個 sudog 來恢復 G1
接收方 G2 接收數據, 並發出一個 receivce ,將 G1 置為 runnable :
同樣的, 接收方 G2 會被阻塞,G2 會創建 sudoq ,存放在 recvq ,基本過程和發送方阻塞一樣。
不同的是,發送方 G1如何恢復接收方 G2,這是一個非常神奇的實現。
理論上可以將 task 入隊,然後恢復 G2, 但恢復 G2後,G2會做什麼呢?
G2會將隊列中的 task 複製出來,放到自己的 memory 中,基於這個思路,G1在這個時候,直接將 task 寫到 G2的 stack memory 中!
這是違反常規的操作,理論上 goroutine 之間的 stack 是相互獨立的,只有在運行時可以執行這樣的操作。
這麼做純粹是出於性能優化的考慮,原來的步驟是:
優化後,相當於減少了 G2 獲取鎖並且執行 memcopy 的性能消耗。
channel 設計背後的思想可以理解為 simplicity 和 performance 之間權衡抉擇,具體如下:
queue with a lock prefered to lock-free implementation:
比起完全 lock-free 的實現,使用鎖的隊列實現更簡單,容易實現
golangaddint64作用
在Go語言中,原子包提供lower-level原子內存,這對實現同步算法很有幫助。Go語言的AddInt64()函數用於將增量自動添加到*addr。此函數在原子包下定義。在這裡,您需要導入sync/atomic軟件包才能使用這些函數。
用法:funcAddInt64(addr*int64,deltaint64)(newint64);
在此,addr表示地址,而delta表示少量大於零的位。
注意:(*int64)是指向int64值的指針。此外,int64包含從-9223372036854775808到9223372036854775807的所有帶符號的64位整數的集合。
返回值:它自動添加addr和delta並返回一個新值。
我們定義了一個add函數,該函數返回調用AddInt64方法返回的輸出。在主函數中,我們定義了一個for循環,該循環將在每個調用中增加’s’的值。在這裡,AddInt64()方法的第二個參數是恆定的,只有第一個參數的值是可變的。但是,上一個調用的輸出將是下一個調用中AddInt64()方法的第一個參數的值,直到循環停止為止。
原創文章,作者:小藍,如若轉載,請註明出處:https://www.506064.com/zh-hant/n/246564.html