channel
//创建无缓冲通道
make(chan,type)
//创建有缓冲通道
make(chan,type,size)
//关闭无缓冲通道时,如果通道中还有未被读取的数据,这将会导致 panic 异常。
//关闭有缓冲通道时,通道中的剩余数据仍然可以被接收者读取,但是无法再向通道发送数据。
sync.Mutex和sync.RWMutex
//Mutex锁会直接锁一部分内容,而RWMutex锁则会对不同的读写情况进行上锁
//Mutex锁
var lock sync.Mutex
lock.lock
lock.unlock
//Mutex读写锁
var RWlock sync.RWMutex
RWlock.Lock//加写锁,遇到其他读写锁则阻塞
RWlock.RLock//加读锁,遇到其他写锁则阻塞,再加读锁不会阻塞
sync.WaitGroup
var wg sync.WaitGroup//声明计数器
wg.Add(2)//增加计数器
wd.Done()//计数器-1
wg.Wait()//等待所有计数器归零
sync.once:
用于高并发状态下只执行一次
var once sync.once
once.Do(func)
done:
// 创建一个无缓冲的同步通道,用于等待所有协程完成
done := make(chan struct{})
<-done
切片slice:
slice预分配,减少扩容次数
切片操作不会复制切片指向的元素
创建一个新的切片会复用原来切片的底层数组----->在已有切片基础上创建切片,底层数组不会被释放
场景:从大切片中新建小切片,原切片较大,底层数组无法释放
解决方法:用copy代替截取切片
badResult:=origin[:-2]
return badResult //底层数组不会被释放
goodResult:=make([]int,2)
copy(goodResult,origin[:-2])
return goodResult //底层数组会被释放
map:
map预分配,减少扩容次数和Rehash的消耗
字符串处理:
//方法1:直接拼接
s:=""
for i:=0;i<n;i++{
s+=str
}
return s
//方法2:使用strings.builder
var builder strings.builder
for i:=0;i<n;i++{
builder.WriteString(str)
}
return builder.String
//方法3:使用bytes.Buffer
buf:=new(bytes.Buffer)
for i := 0; i < n; i++ {
buf.WriteString(str)
}
return buf.String()
//2和3方法可以用Grow方法进行内存预分配,进一步加快效率
builder.Grow(n*len(str))
buf.Grow(n*len(str))
推荐使用strings.builder,
第二种和第三种它们性能相近,拼接最慢
原因:字符串是不可变类型,占用内存大小固定。每次拼接会重新分配内存
而strings.builder和bytes.Buffer底层是[]byte数组。有内容扩容策略,不需要每次拼接都重新分配内存
空结构体:
因为空结构体不占用任何内存空间,可用空结构体代替占位符
m:=make(map[int]struct{})
m[0]= struct{}{}
m:=make(map[int]bool)
m[0]=true
//空结构体更节省空间
实现Set可以用map,只使用键,不使用值
atomic:
用atomic锁比mutex性能更好
原因:mutex通过操作系统实现,atomic通过硬件实现,效率更高
sync.Mutex用于保护一段逻辑,而atomic用于保护一个变量
pprof:
示例项目网站:
blog.wolfogre.com/posts/go-pp…
常用top、list、web三个命令