goroutine锁性能分析

背景

goroutine是go语言并发利器,但是假如有goroutine A 和goroutine B需要同步执行某段程序,没有有效的措施,利用sync.Mutex加锁可以实现。但是sync.Mutex是锁线程的,不是锁协程,可能多个协程都在同一个线程下执行逻辑,协程A获取sync.Mutex锁后,这个线程的其他协程就要切换到别的线程执行逻辑了(go的底层做了处理,这些都是猜测的),这就会带来一定的额外开销。因此,实现了一个goroutine级别的锁,经过对比原生的sync.Mutex性能,提示至1.5倍-5倍的性能

goroutine锁原理

核心代码如下

type RoutineLock struct {
	reqs chan chan bool  //请求锁channel
	unlockChan chan bool //解锁channel
	exit chan bool //退出channel
}

每个goroutine有一个RoutineLock (可以看成是goroutine级别的锁)。假如有goroutine A 和goroutine B需要同步处理某个消息,首先获取A和B的锁权限,这个锁是goroutine级别的锁,处理完毕后,释放A和B的锁

性能对比

taskNum:表示有几个goroutine在处理
countPerTask:表示每个goroutine下,有多少个子goroutine在竞争(sync.Mutex或RoutineLock )

测试条件\锁类型sync.Mutex用时RoutineLock用时
taskNum=50000; countPerTask=500102.44s33.93s
taskNum=1000; countPerTask=5001.80s1.25s
taskNum=2000; countPerTask=5003.42s2.59s
taskNum=3000; countPerTask=50030.43s10.10s
taskNum=4000; countPerTask=50047.41s14.08s
taskNum=3000; countPerTask=100050.50s19.31s
taskNum=200; countPerTask=10000.80s0.53s
taskNum=1000; countPerTask=10003.50s2.58s
taskNum=1000; countPerTask=200081.87s13.22s

通过测试结果可以看出,RoutineLock性能更高

测试结果截图

  1. 在这里插入图片描述
  2. 在这里插入图片描述
  3. 在这里插入图片描述
  4. 在这里插入图片描述
  5. 在这里插入图片描述
  6. 在这里插入图片描述
  7. 在这里插入图片描述
  8. 在这里插入图片描述
  9. 在这里插入图片描述

测试代码


var taskNum = 1000
var countPerTask = 2000
var sleepms = time.Duration(0)

type ThreadLock struct {
	sync.Mutex
}
var threadLocks []*ThreadLock
var routineLocks []*routine.BLock
var nrs []*NewRoutineLock

func init()  {
	threadLocks = make([]*ThreadLock, taskNum)
	for i := 0; i < len(threadLocks); i++ {
		threadLocks[i] = &ThreadLock{}
	}


	routineLocks = make([]*routine.BLock, taskNum)
	for i := 0; i < len(routineLocks); i++ {
		routineLocks[i] = routine.NewRoutineLock()
	}
	nrs = make([]*NewRoutineLock, taskNum)
	for i := 0; i < len(nrs); i++ {
		nrs[i] = NewNewRoutineLock(countPerTask)
	}
}
func TestThreadLockPerformance()  {
	fmt.Printf("taskNum=%v,countPerTask=%v\n", taskNum, countPerTask)
	totalWait := routine.NewAwaitWithoutTimeout()
	value := int32(0)
	totalCount := int32(0)
	for i := 0; i < len(threadLocks); i++ {
		lock := threadLocks[i]
		//lockIndex := i
		go func() {
			count := 0
			tempWait := routine.NewAwaitWithoutTimeout()
			for j := 1; j <= countPerTask; j++ {
				//taskIndex := j
				go func() {
					lock.Lock()
					count++
					if sleepms > 0 {
						time.Sleep(time.Millisecond * sleepms)
					}
					atomic.AddInt32(&value, costTimeOp())
					if count >= countPerTask {
						//fmt.Println("complete", lockIndex)
						tempWait.Complete()
					}
					lock.Unlock()
				}()
			}
			tempWait.Wait()

			if atomic.AddInt32(&totalCount, 1) >= int32(taskNum) {
				totalWait.Complete()
			}
		}()
	}
	totalWait.Wait()
	fmt.Println("value=", value)
}
func TestNewRoutineLockPerformance()  {
	totalWait := routine.NewAwaitWithoutTimeout()
	value := int32(0)
	totalCount := int32(0)
	for i := 0; i < len(nrs); i++ {
		//lock := routineLocks[i]
		routineIndex := i
		lock := nrs[routineIndex].main
		subLocks := nrs[routineIndex].locks
		go lock.Run()
		//lockIndex := i
		go func() {
			count := 0
			tempWait := routine.NewAwaitWithoutTimeout()
			for j := 1; j <= countPerTask; j++ {
				taskIndex := j
				go func() {
					lock.LockWithoutTimeout(subLocks[taskIndex-1])
					count++
					//fmt.Println("routineIndex=", routineIndex, ",taskIndex=", taskIndex)
					if sleepms > 0 {
						time.Sleep(time.Millisecond * sleepms)
					}
					atomic.AddInt32(&value, costTimeOp())
					lock.Unlock(subLocks[taskIndex-1])
					if count >= countPerTask {
						//fmt.Println("complete", lockIndex)
						tempWait.Complete()
					}
				}()
			}
			tempWait.Wait()

			if atomic.AddInt32(&totalCount, 1) >= int32(taskNum) {
				totalWait.Complete()
			}
		}()
	}
	totalWait.Wait()
	for i := 0; i < len(nrs); i++ {
		//lock := routineLocks[i]
		nrs[i].main.Exit()
	}
	fmt.Println("value=", value)
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值