go

go 并发

package main

import (
    "fmt"
    "sync"
)

var wg sync.WaitGroup

func hello() {
    defer wg.Done() // 一定要最后执行
    fmt.Println("hello")
}

func main() {
    wg.Add(1) // 一定要放在 go 前面,不然协程先跑结束,会导致 WaitGroup 计数器出现负数
    go hello()
    fmt.Println("main")
    wg.Wait()       // 一定要放在最后,否则会阻塞直到所有 goroutine 跑完
}
  1. 一个操作系统线程对应用户态多个 goroutine 。
  2. go 程序可以同时使用多个操作系统线程。
  3. goroutine 和 OS 线程是多对多的关系,即 m:n 。

for range 遍历 channel ,只有关闭 channel 才会停止。

Channel 五种情况

从 channel 中 nil 非空非满
接收 (<-ch) 阻塞 接收值 阻塞 接收值
发送 (ch<-) 阻塞 发送值 发送值 阻塞
关闭 panic 读完数据后返回零值 读完数据后返回零值 读完数据后返回零值

select 多路复用

func main () {
    ch := make(chan int, 1)
    for i := 0; i < 11; i++ {
        select {
            case x := <-ch:
                fmt.Println(x)
            case ch <- i:
        }
    }
}

并发安全

// 互斥锁
var lock sync.Mutex

lock.Lock()
x++
lock.Unlock()
// 读写锁
var lock sync.RWMutex

lock.Lock()
x++
lock.Unlock()

lock.RLock()
read()
lock.RUnLock()
// 等待组
var wg sync.WaitGroup

wg.Add(1)
wg.Done()
wg.Wait()
// 只跑一次
var once sync.Once

once.Do(function(){
    instance = &singleton{}
})
// 并发 Map
var m = sync.Map{}

m.Store(key, value)
m.Load(key)
// 原子锁
import "sync/atomic"

atomic.AddInt64(&a.counter, 1)

发表评论