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