ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Sync包

2022-07-24 08:32:04  阅读:174  来源: 互联网

标签:fmt goroutine sync Sync func time main


sync同步包

Mutex互斥锁:

能够保证在同一时间段内仅有一个goroutine持有锁,有且仅有一个goroutine访问共享资源,其他申请锁的goroutine将会被阻塞直到锁被释放。然后重新争抢锁的持有权。

结构体和方法:

type Locker interface {
	Lock()
	UnLocker
}
func (m *Mutex) Lock()
func (m *Mutex) UnLock()
package main

import (
	"fmt"
	"sync"
	"time"
)

func main() {
	//互斥锁
	var lock sync.Mutex
	go func() {
		//加锁
		lock.Lock()
        //释放锁
		defer lock.Unlock()
		fmt.Println("func1 get lock at " + time.Now().String())
		time.Sleep(time.Second)
		fmt.Println("func1 release lock " + time.Now().String())
	}()

	time.Sleep(time.Second / 10)

	go func() {
		lock.Lock()
		defer lock.Unlock()
		fmt.Println("func2 get lock at " + time.Now().String())
		time.Sleep(time.Second)
		fmt.Println("func1 release lock " + time.Now().String())
	}()

	//等待所有goroutine执行完毕
	time.Sleep(time.Second * 4)
}

输出结果:

RWMutex读写锁:

将读锁和写锁分离开来满足以下条件

  • 在同一时间段只能有一个gorountine获取到写锁
  • 在同一时间段可以有任意多个gorountine获取到读锁
  • 在同一时间段只能存在读锁和写锁

结构体和方法:

type RWMutex struct {
	w           Mutex  // held if there are pending writers
	writerSem   uint32 // semaphore for writers to wait for completing readers
	readerSem   uint32 // semaphore for readers to wait for completing writers
	readerCount int32  // number of pending readers
	readerWait  int32  // number of departing readers
}
func (rw *RWMutex) Lock()		//写加锁
func (rw *RWMutex) UnLock()		//写解锁
func (rw *RWMutex) RLock()		//读加锁
func (rw *RWMutex) RUnLock()	//读解锁
package main

import (
	"fmt"
	"strconv"
	"sync"
	"time"
)

var rwLock sync.RWMutex

func main() {
	//获取读锁
	for i := 0; i < 5; i++ {
		go func(i int) {
			rwLock.RLocker()
			defer rwLock.RLocker()
			fmt.Println("read func " + strconv.Itoa(i) + " get lock at " + time.Now().String())
			time.Sleep(time.Second)
		}(i)
	}

	time.Sleep(time.Second / 10)

	//获取写锁
	for i := 0; i < 5; i++ {
		go func(i int) {
			rwLock.Lock()
			defer rwLock.Unlock()
			fmt.Println("write func " + strconv.Itoa(i) + " get lock at " + time.Now().String())
			time.Sleep(time.Second)
		}(i)
	}
	//保证所有的goroutine执行结束
	time.Sleep(time.Second * 4)
}

输出结果:

WaitGroup并发等待数组:

sync.WaitGroup的goroutine会等待预设好的数量的goroutine都提交执行结束后,才会继续往下执行代码,调用Wait方法之前,必须先执行Add方法,还需要保证Done方法和Add添加的等待数量一致,过少会导致等待goroutine死锁,过多会导致程序panic,适用于执行批量操作,等待所有goroutine执行结束后统一返回结果。

package main

import (
	"fmt"
	"strconv"
	"sync"
	"time"
)

func main() {
	var waitGroup sync.WaitGroup
	//添加等待goroutine数量为5
	waitGroup.Add(5)

	for i := 0; i < 5; i++ {
		go func(i int) {
			fmt.Println("work " + strconv.Itoa(i) + " is done at " + time.Now().String())
			//等待1s后减少等待数1
			time.Sleep(time.Second)
			waitGroup.Done()
		}(i)
	}
	waitGroup.Wait()
	fmt.Println("all works are done at " + time.Now().String())
}

输出结果:

Map并发安全字典:

go中的原生map并不是并发安全的,Go语言1.9之后有sync.Map

package main

import (
	"fmt"
	"strconv"
	"sync"
)

var syncMap sync.Map
var waitGroup sync.WaitGroup

func main() {
	routineSize := 5
	//让主线程等待数据添加完毕
	waitGroup.Add(routineSize)
	//并发添加数据
	for i := 0; i < routineSize; i++ {
		go addNumber(i * 10)
	}
	waitGroup.Wait()
	var size int
	//统计数量
	syncMap.Range(func(key, value interface{}) bool {
		size++
		// fmt.Println("key-value pair is ", key, value, " ")
		return true
	})
	fmt.Println("syncMap current size is " + strconv.Itoa(size))
	//获取键为0的值
	value, ok := syncMap.Load(0)
	if ok {
		fmt.Println("key 0 has value", value, " ")
	}
}

func addNumber(begin int) {
	//往syncMap中放入数据
	for i := begin; i < begin+3; i++ {
		syncMap.Store(i, 1)
	}
	//通知数据已添加完毕
	waitGroup.Done()
}

输出结果:

Once只执行一次

提供了初始化延迟功能,done用来记录执行的次数,用m来保证只有一个goroutine在执行Do方法

package main

import (
	"fmt"
	"sync"
)

var once sync.Once
var waitGroup sync.WaitGroup

func main() {
	for i := 0; i < 10; i++ {
		waitGroup.Add(1)
		go func() {
			defer waitGroup.Done()
			once.Do(OnlyOnce)
		}()
	}
	waitGroup.Wait()
}

func OnlyOnce() {
	fmt.Println("only once")
}

输出结果:

Cond同步等待条件:

通过弄个条件控制多个goroutine,不满足条件进行等待,进入等待后即使后续满足条件需要通过Broadcast()或者Signal()来唤醒notifyList内的goroutine

结构体和方法:

type Cond struct {
	noCopy noCopy
    //L用来读写Cond时加锁
    L Locker
    //以下是包外不可见变量
    notify notifyList	//通知列表
    checker copyChecker
}
func NewCond(l Locker) *Cond
//BroadCast用于向所有等待的goroutine发送通知,通知条件已经满足
func (c *Cond) BroadCast()
//Singnal方法用于向特定的单个goroutine发送通知
func (c *Cond) Singnal()
func (c *Cond) Wait()
package main

import (
	"fmt"
	"sync"
	"time"
)

var (
	ready     = false
	singerNum = 3
)

func Sing(singerId int, c *sync.Cond) {
	fmt.Printf("Singer (%d) is ready\n", singerId)
	c.L.Lock()
	for !ready {
		fmt.Printf("Singer (%d) is waiting\n", singerId)
		c.Wait()
	}
	fmt.Printf("Singer (%d) sing a song\n", singerId)
	ready = false
	c.L.Unlock()
}

func main() {
	cond := sync.NewCond(&sync.Mutex{})
	for i := 0; i < singerNum; i++ {
		go Sing(i, cond)
	}
	time.Sleep(3 * time.Second)

	for i := 0; i < singerNum; i++ {
		ready = true
		cond.Broadcast()
		// cond.Signal()
		time.Sleep(3 * time.Second)
	}
}

Broadcast方法测试:

Signal方法测试:

Pool对象池:

并发安全的,大小可伸缩,仅受限于内存。存入Pool的对象可能会在不通知的情况下被释放,比如一些socket长连接就不适合放入Pool内

结构体和方法:

type Pool struct {
    noCopy noCopy
    local unsafe.Pointer	//本地缓冲池指针,每个处理器分配一个,其类型是一个{p}poolLocal的数组
    lcoalSize uintptr		//数组大小
    
    New func() interface {}	//缓存池中没有对象时,调用此方法创建一个
}

//从池中获取对象,如果没有对象调用New创建一个,未设置New返回nil
func (p *Pool) Get() interface{}
//向池中添加对象
func (p *Pool) Put(interface{})

Pool在运行时为每个操作Pool的goroutine所关联的P(GMP模型中的P)都创建一个本地池。在执行Get方法的时候,会先从本地池中获取,如果本地池没有则从其他P的本地池获取。这种特性让Pool的存储压力基于P进行了分摊。

package main

import (
	"fmt"
	"sync"
	"time"
)

var byteSlicePool = sync.Pool{
	New: func() interface{} {
		b := make([]byte, 1024)
		return &b
	},
}

func main() {
	t1 := time.Now().Unix()
	//不使用Pool
	for i := 0; i < 10000000000; i++ {
		bytes := make([]byte, 1024)
		_ = bytes
	}
	t2 := time.Now().Unix()
	//使用Pool
	for i := 0; i < 10000000000; i++ {
		bytes := byteSlicePool.Get().(*[]byte)
		_ = bytes
		byteSlicePool.Put(bytes)
	}
	t3 := time.Now().Unix()
	fmt.Printf("不使用Pool:%d s\n", t2-t1)
	fmt.Printf("使用Pool:%d s\n", t3-t2)
}

输出结果:

标签:fmt,goroutine,sync,Sync,func,time,main
来源: https://www.cnblogs.com/lxuegod/p/16513828.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有