Buildin #
buildin 文档 https://golang.org/pkg/builtin
uintptr #
足够大、可以存放任何指针地址的类型。常用来将指针转换后进行寻址计算。
uintptr is an integer type that is large enough to hold the bit pattern of any pointer.
func Offsetof(x ArbitraryType) uintptr func Sizeof(x ArbitraryType) uintptr func Alignof(x ArbitraryType) uintptr
错误示例 #
func main(){
n := Num{i: "EDDYCJY", j: 1}
nPointer := unsafe.Pointer(&n)
...
ptr := uintptr(nPointer)
njPointer := (*int64)(unsafe.Pointer(ptr + unsafe.Offsetof(n.j)))
...
}
uintptr
类型不能存储在临时变量中。因为从 GC 的角度来看,uintptr
类型的临时变量只是一个无符号整数,并不知道它是一个指针地址。因此当满足一定条件后,ptr
这个临时变量是可能被垃圾回收掉的。
ArbitraryType #
表示任意类型,实际上是一个占位符
ArbitraryType is here for the purposes of documentation only and is not actually part of the unsafe package. It represents the type of an arbitrary Go expression.
type ArbitraryType int
Fmt #
Printf 标准输出 #
动词 | 含义 |
---|---|
%v | 按值的本来值输出 |
%+v | 在 %v 基础上,对结构体字段名和值进行展开 |
%#v | 输出 Go 语言语法格式的值 |
%T | 输出 Go 语言语法格式的类型和值 |
%% | 输出 % 本体 |
%b | 整型以二进制方式显示 |
%o | 整型以八进制方式显示 |
%d | 整型以十进制方式显示 |
%x | 整型以十六进制方式显示 |
%X | 整型以十六进制、字母大写方式显示 |
%U | Unicode 字符 |
%f | 浮点数 |
%p | 指针,十六进制方式显示 |
参考
- https://books.studygolang.com/The-Golang-Standard-Library-by-Example/chapter01/01.3.html
- https://yourbasic.org/golang/fmt-printf-reference-cheat-sheet/
Flag #
func main() {
flag.BoolVar(&all, "all", false, "Set to everything")
flag.Parse()
fmt.Println(all)
}
// true
设置过的 flag 参数记得要 parse 。
Reflect #
获取一个结构体中某个字段的 tag 的信息
func GetStructTagList(i interface{}, tag string) []string {
v := reflect.ValueOf(i)
t := reflect.TypeOf(i)
count := v.NumField()
var ret []string
for i := 0; i < count; i++ {
ret = append(ret, fmt.Sprintf("%v", t.Field(i).Tag.Get(tag)))
}
return ret
}
ValueOf
TypeOf
NumField
Signal #
监听一个信号:
func main() {
sigs := make(chan os.Signal, 1)
done := make(chan bool, 1)
signal.Notify(sigs, syscall.SIGINT)
fmt.Println("start...")
go func() {
switch sig := <-sigs; sig.String() {
case syscall.SIGINT.String():
done <- true
default:
fmt.Println("unknown signal")
}
}()
for {
<-done
fmt.Println("done")
break
}
}
Context #
WithTimeout #
func main() {
ctx, cancel := context.WithTimeout(context.Background(), time.Second*2)
defer cancel()
work(ctx)
}
func work(ctx context.Context) {
done := make(chan bool)
go func(ctx context.Context) {
println("工作中...")
time.Sleep(time.Second * 3)
done <- true
}(ctx)
select {
case <-ctx.Done():
fmt.Println("超时了", ctx.Err())
case <-done:
fmt.Println("执行完成")
}
}
Sync #
Waitgroup #
Add
Done
Wait
Mutex 互斥锁 #
Lock
Unlock
func main() {
var mutex sync.Mutex
count := 0
for i := 0; i < 50; i++ {
go func() {
mutex.Lock()
count++
mutex.Unlock()
}()
}
time.Sleep(time.Second)
fmt.Println(count)
}
// 50
RWMutex 读写锁 #
A RWMutex is a reader/writer mutual exclusion lock. The lock can be held by an arbitrary number of readers or a single writer. The zero value for a RWMutex is an unlocked mutex.
A RWMutex must not be copied after first use.
- Lock 写锁,对读写锁读或写都将阻塞。
- Unlock
- RLock 读锁,只对写操作阻塞。
- RUnlock
RLock() 为“读锁定”,调用“读锁定”后,不能有其他 goroutine 进行写操作,但是可以进行读操作。RUnlock() 为“读解锁”,调用“读解锁”后,会唤醒一个因为要进行“写锁定”而被阻塞的 goroutine。
当 mutex 在 struct 中时,则整个 struct 拥有互斥锁。
Once #
var once sync.Once
once.Do(func() {
fmt.Println("init config ...")
})
Atomic #
func AddT(addr *T, delta T)(new T)
func LoadT(addr *T) (val T)
func StoreT(addr *T, val T)
func SwapT(addr *T, new T) (old T)
func CompareAndSwapT(addr *T, old, new T) (swapped bool)
可以用 atomic 实现 CAS 乐观锁
Pool #
func test() {
// 初始化一个pool
pool := &sync.Pool{
// 默认的返回值设置,不写这个参数,默认是nil
New: func() interface{} {
return 0
},
}
// 看一下初始的值,这里是返回0,如果不设置New函数,默认返回nil
fmt.Println(pool.Get())
fmt.Println(pool.Get())
// 设置一个参数1
pool.Put(1)
pool.Put(1)
// 获取查看结果
fmt.Println(pool.Get())
fmt.Println(pool.Get())
// 再次获取,会发现,已经是空的了,只能返回默认的值。
fmt.Println(pool.Get())
// 0
// 0
// 1
// 1
// 0
}
Cond #
noCopy
noCopy may be embedded into structs which must not be copied after the first use.
https://github.com/golang/go/issues/8005#issuecomment-190753527
Go中没有原生的禁止拷贝的方式,所以如果有的结构体,你希望使用者无法拷贝,只能指针传递保证全局唯一的话,可以这么干,定义一个结构体叫 noCopy
,要实现 sync.Locker
这个接口。
Map #
Unsafe #
Pointer #
Alignof
Sizeof
Offsetof
ArbitraryType(int)
Runtime #
GOMAXPROCS #
func GOMAXPROCS(n int) int
GOMAXPROCS sets the maximum number of CPUs that can be executing simultaneously and returns the previous setting. If n < 1, it does not change the current setting. The number of logical CPUs on the local machine can be queried with NumCPU. This call will go away when the scheduler improves.
疑问
- 在本地设置了最大的 CPU 数量如何验证生效?
Gosched #
runtime.Gosched()用于让出CPU时间片。这就像跑接力赛,A跑了一会碰到代码runtime.Gosched()就把接力棒交给B了,A歇着了,B继续跑。
func say(s string) {
for i := 0; i < 2; i++ {
fmt.Printf("say: %s\n", s)
runtime.Gosched()
fmt.Println(s)
}
}
func test() {
fmt.Println(runtime.GOMAXPROCS(0))
go say("world")
say("hello")
}
// 12
// say: hello
// say: world
// hello
// say: hello
// world
// say: world
// hello
因为 say("hello")
这句占用了时间,等它执行完,线程也结束了,say("world")
就没有机会了。
这里同时可以看出,go 中的 goroutines 并不是同时在运行。事实上,如果没有在代码中通过 runtime.GOMAXPROCS(n) 指定使用多核的话,goroutines 都是在一个线程里的,它们之间通过不停的让出时间片轮流运行,达到类似同时运行的效果。
Stack #
func Stack(buf []byte, all bool) int
Stack formats a stack trace of the calling goroutine into buf and returns the number of bytes written to buf. If all is true, Stack formats stack traces of all other goroutines into buf after the trace for the current goroutine.
IO #
ioutil #
Bufio #
URL #
Timer #
After #
Sleep #
Tick #
Duration #
Time #
格式化基准 2006-01-02 15:04:05