标准库

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 指针,十六进制方式显示

参考

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
	}
}

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.

If a goroutine holds a RWMutex for reading and another goroutine might call Lock, no goroutine should expect to be able to acquire a read lock until the initial read lock is released. In particular, this prohibits recursive read locking. This is to ensure that the lock eventually becomes available; a blocked Lock call excludes new readers from acquiring the lock.

  • Lock
  • RLock
  • RUnlock
  • Unlock

RLock()为“读锁定”,调用“读锁定”后,不能有其他goroutine进行写操作,但是可以进行读操作。RUnlock() 为“读解锁”,调用“读解锁”后,会唤醒一个因为要进行“写锁定”而被阻塞的goroutine。

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
}

fmt 包的应用

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.

疑问

  1. 在本地设置了最大的 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中的goroutins并不是同时在运行。事实上,如果没有在代码中通过 runtime.GOMAXPROCS(n) 指定使用多核的话,goroutins都是在一个线程里的,它们之间通过不停的让出时间片轮流运行,达到类似同时运行的效果。

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

comments powered by Disqus