PalletOne技術講堂之golang程式設計經驗總結
王繼有 Pallet 7月5日
點選上方藍字及時獲取PalletOne最新訊息

講師簡介:
王繼有,PalletOne高階核心開發工程師,8年研發經驗,精通C,C++,Go語言。具有豐富的DHCPv6、ND、RUI協議以及高效能伺服器和物件儲存的設計開發經驗;熟悉區塊鏈P2P網路的設計與開發。
一、unsafe.Pointer型別轉換
[ ]byte轉string
var x = []byte("Hello World!")
var y = *(*string)(unsafe.Pointer(&x))
string轉[ ]byte
var a string = "hello world"
var b = *(*[]byte)(unsafe.Pointer(&a))
結構體和[]byte之間的互轉
參考:
https://studygolang.com/articles/5348
二、golang 幾種常見的字串連線效能比較
如果對字串的拼接有效率要求,那麼最好轉換成位元組用append來操作。
有如下方式:
strings.Join fmt.Sprintf string + bytes.Buffer
v := "ni shuo wo shi bu shi tai wu liao le a?"
var s string
var buf bytes.Buffer //buffer := bytes.NewBuffer(make([]byte, 0, 65536))
s = fmt.Sprintf("%s[%s]", s, v)
s = s + "[" + v + "]"
s = strings.Join([]string{s, "[", v, "]"}, "")
buf.WriteString("[")
buf.WriteString(v)
buf.WriteString("]")
對比結果:
string len: 410000 time of [fmt.Sprintf]= 318.093256ms
string len: 410000 time of [+]= 197.03476ms
string len: 410000 time of [strings.Join]= 439.952002ms
string len: 410000 time of [bytes.Buffer]= 435.764µs
len較小
strings.Join:
10000000 139 ns/op
bytes.Buffer:
10000000 166 ns/op
+:
3000000 429 ns/op
單次呼叫效能:操作符+>strings.Join>=bytes.Buffer>fmt.Sprintf
靈活性:bytes.Buffer>fmt.Sprintf>=strings.Join>操作符+
多次連線字串操作:bytes.Buffer應該是最快的。
參考:
https://www.golangnote.com/topic/148.html
https://gocn.vip/question/265
三、同步機制
Atomic:數字的使用
RWMutex:讀寫鎖
Channel:速度最慢。處理不好使協程阻塞,導致記憶體洩漏
//unsafe.Pointer
參考:
https://www.golangnote.com/topic/225.html
3.1、atomic使用
用原子操作可以替換mutex鎖。其主要原因是,原子操作由底層硬體支援,而鎖則由作業系統提供的API實現。若實現相同的功能,前者通常會更有效率。
32位系統下atomic.AddUint64導致程式崩潰,64位原子操作的呼叫者必須確保指標的地址是對齊到8位元組的邊界。
使用sync.RWMutex來實現互斥,如下:
mutex.Lock()
uint64 += 1
mutex.Unlock()
四、Golang 減小gc 壓力、記憶體洩漏的分析和避免
4.1make([]int, len, cap) 預分配記憶體 make([]int,0,256)
4.2 ioutil.ReadAll()——>bytes.Buffer.ReadFrom——>makeSlice :
buffer := bytes.NewBuffer(make([]byte, 0, resp.ContentLength)
buffer.ReadFrom(res.Body)
body := buffer.Bytes()
4.3channel的釋放
func produce(ch chan<- T, cancel chan struct{}) {
defer close(ch)
select {
case ch <- T{}:
case <- cancel: // 用select同時監聽cancel動作
return
}
}
func consume(ch <-chan T, cancel chan struct{}) {
v := <-ch
err := doSomeThing(v)
if err != nil {
close(cancel) // 能夠通知所有produce退出
return
}
}
for i:=0; i<10; i++ {
go produce( )
}
consume( )
4.4 pprof工具的使用
log.Fatal(http.ListenAndServe(":9876", nil))
go tool pprof http://localhost:9876/debug/pprof/profile
檢視top10函式,分析導致記憶體洩漏的是哪個函式
參考:
https://www.golangnote.com/topic/222.html
http://www.cnblogs.com/yjf512/archive/2012/12/27/2835331.html (pprof或者https://www.cnblogs.com/snowInPluto/p/7403097.html)
五、儘可能少的使用reflect,程式碼理解容易
reflect,中文一般叫做反射。反射機制是指在執行時態能夠呼叫物件的方法和屬性。很多人比較熟悉的是Java的反射機制,其實go語言中也提供了反射機制,import reflect就可以使用。在go語言中,主要用在函式的引數是interface{}型別,執行時根據傳入的引數的特定型別執行不同的動作。
六、相對於math/rand 隨機數,crypto/rand 隨機數更加複雜並且不可預測
6.1、數字加減乘除要SafeMath
https://github.com/OpenZeppelin/openzeppelin-solidity/blob/master/contracts/math/SafeMath.sol
七、go test單元測試
hello.go hello_test.go
測試單個檔案:go test -v hello_test.go hello.go
測試單個函式:go test -v -run TestHello hello_test.go hello.go
壓測單個函式:go test -v -bench BenchmarkHello hello_test.go hello.go
八、PalletOne工程簡單講解
8.1目錄簡單講解
8.2Core下介面示例和事件訂閱、p2p通訊示例
go-palletone /core/coredata.go
go-palletone/ consensus/consensus.go
在ProtocolManager.Start( )開始訂閱共識事件,併發送給對端peer。
對端ProtocolManager.handleMsg( )中處理ConsensusMsg狀態碼
推薦:
GoLang 程式設計經驗分享
https://www.golangnote.com/
程式碼規範
https://www.golangnote.com/topic/24.html
註釋:包、函式、行程式碼修改新增刪除註釋。
區塊鏈世界的IP協議高效能分散式賬本
更多有價值的悄悄話,歡迎加入PalletOne社群
新增PalletOne波波微信
加入社群,諮詢更多訊息
官網:https://pallet.one/
官方郵箱:[email protected]
Telegram:https://t.me/palletchinese
Github:https://github.com/PalletOne
Facebook:https://www.facebook.com/profile.
php?id=100026164972741
更多官方諮詢,關注公眾號獲得