go -sync,同步线程和线程安全,原子操作

10 篇文章 0 订阅

对于sync的使用https://blog.csdn.net/u013474436/article/details/84144349
Mutex互斥锁,一个互斥锁只能同时被一个 goroutine 锁定
RWMutex读写锁,一般用在大量读操作、少量写操作的情况
WaitGroup等待协程组,用于等待一组 goroutine 结束
Cond 条件变量,broadcast操作后对所有的wait有效,signal只对一个wait有效(随机),当执行后不再满足要求则跳出循环,需要配合for使用,达到跳出循环的条件
Pool 临时对象池,适用与无状态的对象的复用,两个方法,get和put
Once 执行一次,onceBody := func() { fmt.Println(“Only once”) } once.Do(onceBody)

https://blog.csdn.net/weixin_38089997/article/details/108793195

主线程等待协程完成

通常采用sync.WaitGroup来达到主线程等待协程的完成后才继续操作的效果

	wg := sync.WaitGroup{}
	if len(groupTypes) > 0 && collection.Collect(groupTypes).Contains("meeting") {
		wg.Add(2)
		go MeetingList(&wg, user, btn.Time, &collaboration)
		go TodayList(&wg, ctx, user, btn.Time, &collaboration, version)
	} else {
		wg.Add(1)
		TodayList(&wg, ctx, user, btn.Time, &collaboration, version)
	}
	wg.Wait()

//方法中添加
defer wg.Done()

原子锁

如果协程内部存在信息信号传递,这个时候需要涉及到原子操作atomic
atomic.LoadInt64(&shotdown)操作能达到同步锁的目的
在这里读取value的值的同时,当前计算机中的任何CPU都不会进行其它的针对此值的读或写操作。
这样的约束是受到底层硬件的支持的。
https://www.jianshu.com/p/228c119a7d0e

//加
atomic.AddUint32(&addr,n)
//减
atomic.AddUint32(*addr,uint32(int32(n)))
//读取
atomic.LoadInt32(&addr)
//...
var (
	shotdown int64 // 该标志向多个goroutine通知状态
	wg       sync.WaitGroup
)
func main() {
	wg.Add(2)
	go doWork("A")
	go doWork("B")
	time.Sleep(1 * time.Second)
	atomic.StoreInt64(&shotdown, 1) //存储新值1
	wg.Wait()
}
func doWork(s string) {
	defer wg.Done()
	for {
		fmt.Printf("Doing homework %s\n", s)
		time.Sleep(2 * time.Second)
		if atomic.LoadInt64(&shotdown) == 1 { //加载读取
			fmt.Printf("Shotdown home work %s\n", s)
			break
		}
	}
}

互斥锁

在方法中,锁整个方法是用 defer mutex.Unlock();mutex.Lock()

// 借助互斥锁实现同步访问共享资源
var (
	counter int
	wg      sync.WaitGroup
	mutex   sync.Mutex // 定义临界区
)
func main() {
	wg.Add(2)
	go incCount(1)
	go incCount(2)
	wg.Wait()
	fmt.Printf("Final Counter: %d\n", counter)
}
func incCount(i int) {
	defer wg.Done()
	for count := 0; count < 2; count++ {
		mutex.Lock()
		{
			value := counter
			runtime.Gosched()
			value++
			counter = value
		}
		mutex.Unlock()
	}
}

协程恢复,协程组处理,互斥锁

	defer util.TryCatch("MeetingList:" + user.Account)
	defer wg.Done()
	defer lock.Unlock()
	lock.Lock()

实现协程的有序执行

场景,协程的操作中,包含了共享资源和非共享资源,如果是执行的共享资源需要执行顺序的时候,就需要制定顺序
以下代码比较神奇的地方在于fmt.Println(“m2等待,”)删除的话,就不会执行fmt.Println(“m2等待结束”)

func TestCound(t *testing.T)  {
	cond := sync.NewCond(&sync.Mutex{})
	count :=2
	fmt.Println("go")
	go m1(cond,&count)
	go m2(cond,&count)
	time.Sleep(6*time.Second)
	fmt.Println("ok")
}
func m2(coud *sync.Cond, count *int) {
	coud.L.Lock()
	defer coud.L.Unlock()
	for *count > 1 {
		fmt.Println("m2等待,,,,,,,,")
		coud.Wait()
		fmt.Println("m2等待结束")
	}
	fmt.Println("m2执行")
}
func m1(coud *sync.Cond, count *int) {
	coud.L.Lock()
	*count--
	time.Sleep(3*time.Second)
	fmt.Println("m1执行")
	coud.Broadcast()
	coud.L.Unlock()
}

在实际操作过程中,先看代码

	wg := sync.WaitGroup{}
	var count int32 = 2
	coud := sync.NewCond(&sync.Mutex{})
	if len(groupTypes) > 0 && collection.Collect(groupTypes).Contains("meeting") {
		wg.Add(2)
		go MeetingList(&wg, coud, &count, user, btn.Time, &collaboration)
		go TodayList(&wg, coud, &count, ctx, user, btn.Time, &collaboration, version)
	} else {
		count--
		wg.Add(1)
		TodayList(&wg, coud, &count, ctx, user, btn.Time, &collaboration, version)
	}
	wg.Wait()

func MeetingList(){
defer wg.Done()
//... 此处省略其他的处理
//共享资源的处理
	cond.L.Lock()
	*count--
	collaboration.Groups = append(collaboration.Groups, group)
	cond.Broadcast()
	cond.L.Unlock()
}
func TodayList(){
	defer util.TryCatch("TodayList:" + user.Account)
	defer wg.Done()
	defer cond.L.Unlock()
//... 此处省略其他的处理
//共享资源的处理
	cond.L.Lock()
	for *count > 1 {
		logger.Info("等待中:",*count)
		cond.Wait()
	}
	//然后共享资源的处理
}

第一测试的发现协程等待有效,但是第二天测试发现请求一直在等待,不用猜都知道是死循环了,打印日志果然,第二个线程进入等待,为啥会这样呢,因为这里是meeting的处理判断数据为null的时候就直接返回了,这个时候,计数还是2,就导致了死循环,另外有一个点就是这里对计数的操作需要原子操作吗?有锁的情况下,实际上是不用的

map操作锁

sync.Map

var BusinessDataHisColls sync.Map
var getBusinessDataHisCollLock sync.Mutex

func GetBusinessDataHisColl() *mongo.Collection {
	collName := "business_data_his_" + time.Now().Format("2006-01")
	coll, ok := BusinessDataHisColls.Load(collName)
	if !ok || coll == nil {
		getBusinessDataHisCollLock.Lock()
		coll, ok := BusinessDataHisColls.Load(collName)
		if !ok || coll == nil {
			coll = Client.Database(mongoConfig.Database).Collection(collName)
			BusinessDataHisColls.Store(collName, coll)
		}
		getBusinessDataHisCollLock.Unlock()
	}
	return coll.(*mongo.Collection)
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值