这些 tips 是有本人日常开发所遇到过的 issue 后记录下来的解决方法,会不定期更新。
2021-01-02T06:29:29+08:00
言简意赅的go scheduler解释 #
concurrency好,scheduler就得好。
Rob Pike的'Concurrency Is Not Parallelism'
scheduler的成本主要是:
a) communication
b) migration
scheduler方式主要有2种:
work-sharing: 自己忙就往其他process上扔
work-stealing: 自己空闲就从其他process上偷几个来干
go用的是work-stealing,借鉴于CILK设计论文,tokudb在最早的时候也用了CILK。
粗讲很简单:
就是每个P(process structure)上有个 runnable goroutines list, goroutine结束一个就从这个list摘除一个,如果list空了,那就去“偷”活干,communication和migration都比较低。
go tooling in action #
2017-09-02 14:29:29
go 的工具链对于不管是在编码工作,编码规范,性能分析 tunning 方面基本说是必备的,这个视频 以及提供了 配套练习 简洁快速干货,值得一看。
internal package #
在使用goimport进行包自动引入时,如果不同项目含有一样的包后缀和方法,可能会出现引入错误,而放在 internal 文件夹下面的 package 只能被当前的项目所引用就能很好的解决这个瘙痒问题。如果把 internal 放在 project 下面的第一层,那么 internal 里面的包就只能被该 project 引用了。
version on compilation #
对于不定时发布新版本程序在线上的项目而言,当出现问题时往往需要查看当前发布的是哪一个版本的程序(或者哪一次 commit); 一般进行新版本程度分发部署和不同机子上都先在本地编译成 executal app 再同步到各个环境上,只要在编译的命令中指定变量的值为版本号,可以用 git commit 的 hash 值来充当;一般可以写个 bash 或者 makefile 这种 script 来进行自动编译。
adding-version.go
tag version on vendor package #
2022-08-20 09:05:48
像用go mod 时通过$targetVersionPackage.Version
的方式可以给Version
赋值打上版本信息,但对于vendor管理包的方式则是
使用$projectPackage/vendor/$targetVersionPackage.Version
的方式去指定Version
的值
vendor package management #
不同项目中使用 github.com 的第三方包存在版本更新不同步的情况,把这些三方包放到 vendor 目录中,就可以让项目使用 vendor 下面的 package 而不会引用$GOPATH/src这种共用版本的 package, 项目单据维护自己 vendor 下的三方包即可。
exit goroutines gracefully #
WaitGroup 来等待和确保所有 goroutine 退出
已经关闭的 channel 是 readable 的,可以用来通知 goroutine 退出;
exit := make(chan struct{})
var wg sync.WaitGroup
const count = 9
wg.Add(count)
for i := 0; i < count; i++ {
j := i
go func(goID int) {
for {
select {
case <-exit:
wg.Done()
println("exit ", goID)
return
}
}
}(j)
}
close(exit)
wg.Wait()
reference:Close Channels Gracefully in Golang
JSON2Go #
https://mholt.github.io/json-to-go/
利用示例转换成 go struct 一件很省心的事。
get proxy issue #
如果要让 go get
走代理,可以在调用命令时设置 proxy
e.g.
https_proxy=http://127.0.0.1:7777 go get -u golang.org/x/tools/...
如果只有 sock5 代理,使用 cow 将 http 或者 https 转发代理到 sock5
e.g.
安装好 cow 后,设置~/.cow/rc 文件,启动 cow 即可
cd $GOPATH/bin && curl -L git.io/cow | bash
listen = http://127.0.0.1:7777
proxy = socks5://127.0.0.1:1080
go get vim-go binary tools
https_proxy=http://127.0.0.1:7777 go get -u -v golang.org/x/tools/...
https_proxy=http://127.0.0.1:7777 go get -u -v github.com/zmb3/gogetdoc/...
https_proxy=http://127.0.0.1:7777 go get -u -v github.com/golang/lint/golint
https_proxy=http://127.0.0.1:7777 go get -u -v github.com/kisielk/errcheck
https_proxy=http://127.0.0.1:7777 go get -u -v github.com/josharian/impl
go range issue #
each time when you are using range
, just think about it like this:
var value Foo
for var i := 0; i < len(list); i++ {
value = list[i]
list2[i] = &value
}
traps like bellow should be escaped:
for _, v := range ss {
go f(){
//do something with v
} ()
}
or
smap := make(map[int]*A, 3)
for k, v := range ss {
smap[k] = &v
}
limit goroutine spawning #
2020-06-25 22:51:43
主要是 申请归还 的思路,根据block channel, 当想要启用一个goroutine来执行任务时,尝试写入channel,如果能写入说明目前运行的goroutine数量还未达到阀值,反之blocking的时候只有在 一个完成任务的goroutine从channel中取出占位资源后,这样就有一个空闲的goroutine可用了,部分关键代码如下:
const maxGoroutines = 10
guard := make(chan struct{}, maxGoroutines)
for {
select {
case <-exit:
return
case oneJob := <-jobQueuePending:
//写入 channel
guard <- struct{}{}
go func() {
//归还资源
<-guard
}()
}
}
也或者同时启用 maxGoroutines 个goroutine,每个goroutine去同时抢一个channel上的任务
var wgWorkers sync.WaitGroup
for i := 0; i < maxGoroutines; i++ {
wgWorkers.Add(1)
go func(workerIndex int) {
defer wgWorkers.Done()
for {
select {
case <-exit:
return
case oneQa := <-queuePending:
select {
case queuePersist <- oneQa:
case <-exit:
return
}
}
}
}(i)
}
wgWorkers.Wait()
skip checking some packages #
2021-01-26 10:17:32
比如不想检查项目中的 cmd 包
PACKAGES2CHECK ?= $(shell $(GO) list ./... | grep -v /cmd/)
vet:
$(GO) vet $(PACKAGES2CHECK)