Golang 标准库 sync

1. Mutex

互斥锁,等同于Linux下的pthread_mutex_t

func (m *Mutex) Lock()
func (m *Mutex) Unlock()
// 多个线程同时运行,获的Mutex锁的线程优先运行,其余线程阻塞等待
func testMutex() {
	mutex := sync.Mutex{}

	for i := 0; i < 10; i++ {
		go func(i int) {
			mutex.Lock()
			defer mutex.Unlock()

			fmt.Println(i)
			time.Sleep(time.Second)
		}(i)
	}
}

2. RWMutex

读写锁,等同于Linux下的pthread_rwlock_t

// 写
func (rw *RWMutex) Lock()
func (rw *RWMutex) Unlock()

// 读
func (rw *RWMutex) RLock()
func (rw *RWMutex) RUnlock()
// 写请求在读锁和写锁时都必须等待
// 读请求只在写锁时阻塞等待
func testRWMutex() {
	rwMutex := sync.RWMutex{}

	for i := 0; i < 10; i++ {
		go func(i int) {
			rwMutex.Lock()
			defer rwMutex.Unlock()

			fmt.Println("Write Mutex:", i)
		}(i)

		go func(i int) {
			rwMutex.RLock()
			defer rwMutex.RUnlock()

			fmt.Println("Read Mutex:", i)
		}(i)
	}
}

3. Cond

条件变量,等同于Linux下的pthread_cond_t

type Cond struct {
    noCopy noCopy
  
    // L is held while observing or changing the condition
    L Locker
  
    notify  notifyList
    checker copyChecker
}

func NewCond(l Locker) *Cond
func (c *Cond) Broadcast()
func (c *Cond) Signal()
func (c *Cond) Wait()
func testCond() {
	cond := sync.NewCond(&sync.Mutex{})

	cond.L.Lock() // 1. 上锁
	defer cond.L.Unlock()

	go func() {
		fmt.Println("go wait lock.")
		cond.L.Lock() // 2. 等待Wait解锁

		defer cond.L.Unlock() // 5. 解锁后触发 wait
		defer fmt.Println("go unlock.")

		fmt.Println("go locked.")
		cond.Signal() // 4. 触发 wait 等待锁
	}()

	time.Sleep(time.Second)

	fmt.Println("start wait.")
	cond.Wait() // 3. 立即解锁并触发一个阻塞线程(如果没有则不触发)后立即再上锁等待Signal信号

	fmt.Println("wait finished.")
}

4. WaitGroup

等待组

func (wg *WaitGroup) Add(delta int) // 新增 delta 个任务
func (wg *WaitGroup) Done() // 完成一个任务,计算器减1
func (wg *WaitGroup) Wait() // 主线程等待,直到计数器为0
// Add增加等待计数;Done减少等待计数;当计数为0时触发Wait
func testWaitGroup() {
	wg := sync.WaitGroup{}

	for i := 0; i < 10; i++ {
		wg.Add(1)

		go func(i int) {
			time.Sleep(time.Second)
			fmt.Println("go:", i)
			wg.Done()
		}(i)
	}

	fmt.Println("start wait.")
	wg.Wait()
	fmt.Println("wait finish.")
}

5. Once

只执行一次

type Once struct {
    m    Mutex
    done uint32
}

func (o *Once) Do(f func())
func testOnce() {
	once := sync.Once{}

	for i := 0; i < 10; i++ {
		go func(i int) {
			once.Do(func() {
				fmt.Println("Do once:", i)
			})

			fmt.Println("go:", i)
		}(i)
	}
}

6. Map

线程安全map

func (m *Map) Delete(key interface{})
func (m *Map) Load(key interface{}) (value interface{}, ok bool)
func (m *Map) LoadAndDelete(key interface{}) (value interface{}, loaded bool)
func (m *Map) LoadOrStore(key, value interface{}) (actual interface{}, loaded bool)
func (m *Map) Range(f func(key, value interface{}) bool)
func (m *Map) Store(key, value interface{})
func testMap() {
	sm := sync.Map{}

	for i := 0; i < 10; i++ {
		go func(i int) {
			v := fmt.Sprintf("StrVal=%d", i)
			_, ok := sm.LoadOrStore(i, v)
			if !ok {
				fmt.Println("Stored index:", i)
			}
		}(i)

		go func(i int) {
			if v, ok := sm.Load(i); ok {
				fmt.Printf("Loaded %v: %v\n", i, v)
			}
		}(i)
	}
}

7. Pool

线程安全对象池

作用:保存和复用临时对象,以减少内存分配,降低GC压力

获取对象过程:

  1. 固定到某个P,尝试从私有对象获取,如果私有对象非空则返回该对象,并将私有对象清掉
  2. 如果私有对象为空,就去当前子池的共享列表中获取(需要加锁)
  3. 如果当前子池列表也为空,就尝试去其他P的子池的共享列表偷一个(需要加锁)
  4. 如果其他子池都是空的,直接返回用户指定的New 函数对象

注意点:

  • 用途仅仅是增加对象重用的几率,减少gc的负担,但依旧有不小的开销
  • GC会将Pool清理掉
  • Get不能保证将Put进去的全部取出来
type Pool struct {
    noCopy noCopy

    local     unsafe.Pointer // local fixed-size per-P pool, actual type is [P]poolLocal
    localSize uintptr        // size of the local array

    // New optionally specifies a function to generate
    // a value when Get would otherwise return nil.
    // It may not be changed concurrently with calls to Get.
    New func() interface{}
}

func (p *Pool) Get() interface{}
func (p *Pool) Put(x interface{})
func testPool() {
	pool := &sync.Pool{
		New: func() interface{} {
			return -1
		},
	}

	for i := 0; i < 10; i++ {
		go func(i int) {
			pool.Put(i)
		}(i)
	}

	for i := 0; i < 20; i++ {
		go func() {
			v := pool.Get()
			fmt.Println("Get:", v)
		}()
	}
}

func testPool2() {
	pool := &sync.Pool{
		New: func() interface{} {
			return -1
		},
	}

	for i := 0; i < 10; i++ {
		pool.Put(i)
	}

	time.Sleep(time.Second)

	// 不一定取到,且顺序不一致
	for i := 0; i < 10; i++ {
		fmt.Println(pool.Get())
	}
}

字节拼接:

func main() {
	bufferPool := &sync.Pool{
		New: func() interface{} {
			return new(bytes.Buffer)
		},
	}

	// 获取缓冲区,存储字节序列
	buf := bufferPool.Get().(*bytes.Buffer)

	var a uint32 = 121
	var b uint32 = 3434

	// 将数据转为字节序列
	err := binary.Write(buf, binary.LittleEndian, a)
	if err != nil {
		panic(err)
	}

	err = binary.Write(buf, binary.LittleEndian, b)
	if err != nil {
		panic(err)
	}

	// 拼接后的结果
	fmt.Printf("% x\n", buf.Bytes())

	// 缓冲使用完毕,必须重置并放回Pool中
	buf.Reset()
	bufferPool.Put(buf)
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值