王继有 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
更多官方咨询,关注公众号获得