goroutine

func test() {
    for {
        fmt.Println("this is test")
        time.Sleep(time.Second)
    }
}

func main() {
    go test() // 新建一个携程

    for {
        fmt.Println("this is main")
        time.Sleep(time.Second)
    }
}

runtime调度器,几个包的方法

  • Gosched:让当前线程让出 cpu 以让其它线程运行,它不会挂起当前线程,因此当前线程未来会继续执行
  • NumCPU:返回当前系统的 CPU 核数量
  • GOMAXPROCS:设置最大的可同时使用的 CPU 核数
  • Goexit:退出当前 goroutine(但是defer语句会照常执行)
  • NumGoroutine:返回正在执行和排队的任务总数
  • GOOS:目标操作系统

channel 通道

ch := make(chan int)    // 创建缓冲区
ch2 := make(chan string, 2) // 创建一个带缓冲区
ch <- 1    // 将1发送到通道
v := <-ch // v接收ch

死锁

读写有一端永远无法执行 无缓存chnnel需要同时操作,否则会产生死锁! fatal error: all goroutines are asleep - deadlock!

func main() {
    ch := make(chan int)
    ch <- 1
    v := <-ch
    fmt.Println(v)
}

WaitGroup

WaitGroup 用于等待一组 goroutine 结束

func main() {
    var wg sync.WaitGroup
    for i := 0; i < 5; i++ {
        wg.Add(1) //计数器加1
        go func(i int) {
            defer wg.Done() //计数器减1
            fmt.Println(i)
        }(i)
    }
    wg.Wait() //等待执行完毕
}

互斥锁

保护公共数据。被锁住后,只有成功加锁的Goroutine能正常访问。其他go程阻塞在锁的等待事件上。

var x = 0
var wg sync.WaitGroup
var lock sync.Mutex

func add() {
    for i := 0; i < 1000000; i++ {
        lock.Lock() //上锁
        x = x + 1
        lock.Unlock() //解锁
    }
    wg.Done()
}

func main() {
    wg.Add(2)
    go add()
    go add()
    wg.Wait()
    fmt.Println(x)    // 未上锁1025765左右 上完锁2000000
}

读写锁

读共享,写独占。
写锁优先级高于读锁。
锁只有一把,但是有两种属性。读属性加锁、写属性加锁。
//    定义
var rwl sync.RWMutex
//    加锁
rwl.RLock()            rwl.Lock()
//    解锁
rwl.RUnlock            rwl.UnLock()

当读大于写的时候 读写互斥锁比互斥锁效率高 因为当读的时候不需要等

var (
    i      = 0
    wg     sync.WaitGroup
    rwLock sync.RWMutex
)

func read() {
    defer wg.Done()
    rwLock.RLock() // 加读锁
    fmt.Println(i)
    rwLock.RUnlock() // 解锁
}

func write() {
    defer wg.Done()
    rwLock.Lock() // 加写锁
    i++
    rwLock.Unlock() // 解锁
}

func main() {
    start := time.Now()
    for i := 0; i < 100; i++ {
        wg.Add(1)
        go write()
    }
    for i := 0; i < 1000; i++ {
        wg.Add(1)
        go read()
    }
    wg.Wait()
    fmt.Println(time.Now().Sub(start))
}

Once

Once只执行一次

type Once struct {
    // contains filtered or unexported fields
}

Once 的作用是多次调用但只执行一次,Once 只有一个方法,Once.Do(),向 Do 传入一个函数,这个函数在第一次执行 Once.Do() 的时候会被调用,以后再执行 Once.Do() 将没有任何动作,即使传入了其它的函数,也不会被执行,如果要执行其它函数,需要重新创建一个 Once 对象。

func main() {
    var o sync.Once
    one := func() {
        fmt.Println("我被执行了")
    }

    for i := 0; i < 10; i++ {
        go func() {
            o.Do(one)
            // one()
        }()
        go func() {
            o.Do(one)
            // one()
        }()
    }
    time.Sleep(time.Second * 3)
}

sync.Map

Go语言内置的map不是并发安全的

func (m *Map) Delete(key interface{})
func (m *Map) Load(key interface{}) (value interface{}, ok bool)
func (m *Map) LoadOrStore(key, value interface{}) (actual interface{}, loaded bool)
func (m *Map) Store(key, value interface{})
func (m *Map) Range(f func(key, value interface{}) bool)
var m = sync.Map{} // 无需初始化直接使用
func main() {
    wg := sync.WaitGroup{}
    for i := 0; i < 100; i++ {
        wg.Add(1)
        go func(n int) {
            key := strconv.Itoa(n)
            m.Store(key, n)
            value, _ := m.Load(key)
            fmt.Printf("key=:%v, value=:%v\n", key, value)
            wg.Done()
        }(i)
    }
    wg.Wait()
}

atomic 原子

方法解释
func LoadInt32(addr *int32) (val int32) func LoadInt64(addr *int64) (val int64) func LoadUint32(addr *uint32) (val uint32) func LoadUint64(addr *uint64) (val uint64) func LoadUintptr(addr *uintptr) (val uintptr) func LoadPointer(addr *unsafe.Pointer) (val unsafe.Pointer)读取操作
func StoreInt32(addr *int32, val int32) func StoreInt64(addr *int64, val int64) func StoreUint32(addr *uint32, val uint32) func StoreUint64(addr *uint64, val uint64) func StoreUintptr(addr *uintptr, val uintptr) func StorePointer(addr *unsafe.Pointer, val unsafe.Pointer)写入操作
func AddInt32(addr *int32, delta int32) (new int32) func AddInt64(addr *int64, delta int64) (new int64) func AddUint32(addr *uint32, delta uint32) (new uint32) func AddUint64(addr *uint64, delta uint64) (new uint64) func AddUintptr(addr *uintptr, delta uintptr) (new uintptr)修改操作
func SwapInt32(addr *int32, new int32) (old int32) func SwapInt64(addr *int64, new int64) (old int64) func SwapUint32(addr *uint32, new uint32) (old uint32) func SwapUint64(addr *uint64, new uint64) (old uint64) func SwapUintptr(addr *uintptr, new uintptr) (old uintptr) func SwapPointer(addr *unsafe.Pointer, new unsafe.Pointer) (old unsafe.Pointer)交换操作
func CompareAndSwapInt32(addr *int32, old, new int32) (swapped bool) func CompareAndSwapInt64(addr *int64, old, new int64) (swapped bool) func CompareAndSwapUint32(addr *uint32, old, new uint32) (swapped bool) func CompareAndSwapUint64(addr *uint64, old, new uint64) (swapped bool) func CompareAndSwapUintptr(addr *uintptr, old, new uintptr) (swapped bool) func CompareAndSwapPointer(addr *unsafe.Pointer, old, new unsafe.Pointer) (swapped bool)比较并交换操作
package main

import (
    "fmt"
    "sync"
    "sync/atomic"
    "time"
)

type Counter interface {
    Inc()
    Load() int64
}

// 普通版
type CommonCounter struct {
    counter int64
}

func (c CommonCounter) Inc() {
    c.counter++
}

func (c CommonCounter) Load() int64 {
    return c.counter
}

// 互斥锁版
type MutexCounter struct {
    counter int64
    lock    sync.Mutex
}

func (m *MutexCounter) Inc() {
    m.lock.Lock()
    defer m.lock.Unlock()
    m.counter++
}

func (m *MutexCounter) Load() int64 {
    m.lock.Lock()
    defer m.lock.Unlock()
    return m.counter
}

// 原子操作版
type AtomicCounter struct {
    counter int64
}

func (a *AtomicCounter) Inc() {
    atomic.AddInt64(&a.counter, 1)
}

func (a *AtomicCounter) Load() int64 {
    return atomic.LoadInt64(&a.counter)
}

func test(c Counter) {
    var wg sync.WaitGroup
    start := time.Now()
    for i := 0; i < 1000; i++ {
        wg.Add(1)
        go func() {
            c.Inc()
            wg.Done()
        }()
    }
    wg.Wait()
    end := time.Now()
    fmt.Println(c.Load(), end.Sub(start))
}

func main() {
    c1 := CommonCounter{} // 非并发安全
    test(c1)
    c2 := MutexCounter{} // 使用互斥锁实现并发安全
    test(&c2)
    c3 := AtomicCounter{} // 并发安全且比互斥锁效率更高
    test(&c3)
}