欢迎访问我的博客,你的支持,是我最大的动力!

Go语言学习笔记(10)-综合技巧

Linux 小马奔腾 295℃ 评论
目录:
[显示]
go执行流程

使用select{}阻塞main函数

让main函数不退出,select {}可阻塞主函数,但需要有线程在运行

redis 使用

new开辟内存

只声明未赋值的变量,会自动初始化为零值,若是引用类型或指针,它们的零值是nil,nil类型不能直接赋值,因此需要通过new开辟一个内存,或指向一个变量

 

go二进制文件删除调试符号

默认情况下,go编译出的程序在运行出错时,会输出在哪个线程哪个文件哪个函数哪行出错的调试信息

go build -ldflags "-s -w" [<your/package]
-s 禁用symbol表
-w 禁用DWARF

这样编译出的程序会减少文件大小约20%

go二进制文件使用UPX加壳

使用upx可压缩go二进制文件到原始大小30%左右
运行时先在内存中解压,再执行,性能影响非常小

下载最新版本的upx程序
wget https://github.com/upx/upx/releases/download/v3.95/upx-3.95-amd64_linux.tar.xz
tar xvf upx-3.95-amd64_linux.tar.xz
upx [-123456789dlthVL] [-qvfk] [-o file] file..
upx -k test
选项:
-1,-9 压缩级别
-d 解压
-l 列出压缩文件,显示压缩比、格式等信息
-t 测试压缩文件
-k 备份源始文件

可变参数

定时器

time.Ticker 循环触发, time.Timer 仅运行一次, 二者都向通道C发送当前时间

channel 阻塞的情况

channel 未初始化时

关闭:panic
写入:阻塞
读取:阻塞

channel 无缓存

关闭:正常关闭
写入:channel为空时 -> 正常;channel不为空时 -> 阻塞
读取:channel为空时 -> 阻塞;channel不为空时 -> 正常

channel 有缓存

关闭:正常关闭
写入:缓存未满时 -> 正常;缓存满时 -> 阻塞
读取:缓存未满时 -> 正常;缓存为空时 -> 阻塞

channel 已关闭

再次关闭:panic
读取:若channel非空-> 取得数据;若channel为空 -> 取得该类型零值
写入:panic

for-rangeclose后,循环才会结束
会一直从 channel 中读取数据,直到有 goroutine 对改 channel 执行 close 操作,循环才会结束
 select:全部阻塞才阻塞
select 可以同时监听多个 channel 的写入或读取,选择未阻塞的case执行,若多个case均未阻塞,随机挑选一个case执行
select 若所有case均阻塞,且定义了default模块,则执行default模块,若未定义default,则阻塞
select 中某channel关闭时,会读取到该类型的0值,即当channel中有内容或被关闭时,select正常取到数据
select 使用break可跳出select块

说明:
1、channel一定要初始化后才能进行读写操作,否则会永久阻塞
2、关闭一个未初始化的channel会产生panic
3、重复关闭同一个channel会产生panic
4、向一个已关闭的channel中发送消息会产生panic
5、从已关闭的channel中读取消息不会产生panic,且能读取出channel中还未被读取的消息,若消息均已读出,会读取到类型的零值
6、从一个已关闭的channel中读取消息永远不会阻塞,并且会返回一个为false的标记,可以此判断channel是否关闭
7、关闭channel会产生一个广播机制,所有从该channel读取消息的goroutine都会收到消息
8、从无缓存的channel中读取消息会阻塞,直到该channel中有消息
9、向无缓存的channel中写入消息会阻塞,直到该channel中没有消息

协程池

防止协程无限制增加

defer 的使用

defer的标准用法:

defer函数定时,对外部变量的引用有两种方式:函数参数 和 闭包
作为函数参数时,参数在定义时cache,使用时和定义时一致
作为闭包、引用时,在defer真正使用时根据当前上下文确定,使用时可能已经不是定义时的值了
# 所有匿名函数都是闭包
return xxx
defer中的return:
1、返回值 = xxx
2、调用defer函数  #这里可以操作返回值
3、空的return  #此时返回值可能被defer修改了

参考:Golang之轻松化解defer的温柔陷阱

打印变量类型及值 godump

项目地址:https://github.com/liudng/godump

安装:go get github.com/liudng/godump
使用:
import github.com/liudng/godump
godump.Dump(val)    # 其中val是变量名

另外一个工具:
项目地址:https://github.com/davecgh/go-spew
安装:go get -u github.com/davecgh/go-spew/spew
使用:
import "github.com/davecgh/go-spew/spew"
spew.Dump(val)  # 其中val是变量名

类型断言

引用/指针 &和*
& 仅用于生成操作数对应的地址,即用于生成指针
有两种情况:
-> 一个是类型 * Type 代表是一个指针类型
-> 一个是指针 * Pointer 代表获取指针对应的值,取值
go mod

go mod 是不依赖$GOPASS的程序组织方式

使用示例

在任意目录下,非$GOPASS目录
# 下载一个项目
git clone https://github.com/snowlyg/IrisApiProject.git
# 进入项目
cd IrisApiProject
# 初始化mod 其中本地用模块名可任意起  若是要发布到github供别人使用,命令类似于github.com/snowlyg/IrisApiProject
go mod init IrisApiProject   # 会生成go.mod文件
# 可直接开始编译  会自动分析包依赖并下载至$GOPATH/pkg/mod目录下
go build .   # 编译会下载一次所有依赖
# 若希望将依赖放于vendor目录下
go mod vendor
# 依赖vendor下的资源编译  不需要下载
go build -mod vendor
goproxy 代理
在国内,类似golang.org/x/crypto等包往往无法下载
可以设置Go Module Proxy解决
export GOPROXY="https://athens.azurefd.net"         #这里使用了微软提供的代理
export GOPROXY=https://goproxy.io   #另一个代理
# 查看
go env

其他方案:
从Github代码库clone
使用命令行代理 https_proxy环境变量
## https_proxy=http://192.168.1.100:1080 go get -u golang.org/x/tools
使用go mod replace
使用gopm类似的工具
## go get github.com/gpmgo/gopm
## go install github.com/gpmgo/gopm
## gopm get -g -v -u golang.org/x/tools/cmd/goimports

GoCenter,项目:https://github.com/jfrog/gocenter
使用:
GOPROXY=https://gocenter.io
goc build

go vet

# 检查file.go,能发现无法执行到的代码、函数的错误调用(如fmt.Printf中参数没有对齐format)
go vet file.go

使用信号退出

默认 go应用在收到SIGTERM信号后会直接退出主进程,此时若有未处理完成的事务,会导致过程异常中断,影响服务质量
通过显式捕获SIGTERM信号,可主动采取措施优雅结束进程

sync包

sync.Once 保证函数仅执行一次
once sync.Once
once.Do(function_name)

 

 

 

 

转载请注明:轻风博客 » Go语言学习笔记(10)-综合技巧

喜欢 (0)or分享 (0)