首页 > 其他分享 >golang channel 和 mutex 及原子操作 用于并发控制的性能对比

golang channel 和 mutex 及原子操作 用于并发控制的性能对比

时间:2024-07-24 10:21:42浏览次数:9  
标签:wg cnt numsWorkers sync golang mutex time var channel

场景:
对同个数加 10w 次,看耗费时间,这里没有用 benchmark 测试,在意的请略过。

以下是测试代码:

package main

import (
	"fmt"
	"sync"
	"sync/atomic"
	"testing"
	"time"
)


func TestCount(t *testing.T) {
	var cnt int
	var wg sync.WaitGroup
	numsWorkers := 100000
	start := time.Now()

	for i := 0; i < numsWorkers; i++ {
		wg.Add(1)
		go func() {
			defer wg.Done()
			cnt++
		}()
	}

	wg.Wait()
	fmt.Printf("Result, cnt: %d, time cost: %v\n", cnt, time.Now().Sub(start))
}


func TestCountWithMutex(t *testing.T) {
	var cnt int
	var wg sync.WaitGroup
	var mu sync.Mutex
	numsWorkers := 100000
	start := time.Now()

	for i := 0; i < numsWorkers; i++ {
		wg.Add(1)
		go func() {
			defer wg.Done()
			mu.Lock()
			defer mu.Unlock()
			cnt++
		}()
	}

	wg.Wait()
	fmt.Printf("Result, cnt: %d, time cost: %v\n", cnt, time.Now().Sub(start))
}

func TestCountWithChannel(t *testing.T) {
	var cnt int
	var wg sync.WaitGroup
	lock := make(chan struct{}, 1) // cap > 1, unsafe
	numsWorkers := 100000
	start := time.Now()

	for i := 0; i < numsWorkers; i++ {
		wg.Add(1)
		go func() {
			defer wg.Done()
			lock <- struct{}{}

			cnt++
			<- lock
		}()
	}

	wg.Wait()
	fmt.Printf("Result, cnt: %d, time cost: %v\n", cnt, time.Now().Sub(start))
}

func TestCountWithAtomic(t *testing.T) {
	var cnt int64
	var wg sync.WaitGroup
	numsWorkers := 100000
	start := time.Now()

	for i := 0; i < numsWorkers; i++ {
		wg.Add(1)
		go func() {
			defer wg.Done()
			atomic.AddInt64(&cnt, 1)
		}()
	}

	wg.Wait()
	fmt.Printf("Result, cnt: %d, time cost: %v\n", cnt, time.Now().Sub(start))
}

以下实测实结果:

$ go test -v
=== RUN   TestCount
Result, cnt: 98431, time cost: 24.45ms
--- PASS: TestCount (0.02s)
=== RUN   TestCountWithMutex
Result, cnt: 100000, time cost: 38.1108ms
--- PASS: TestCountWithMutex (0.04s)
=== RUN   TestCountWithChannel
Result, cnt: 100000, time cost: 102.0231ms
--- PASS: TestCountWithChannel (0.10s)
=== RUN   TestCountWithAtomic
Result, cnt: 100000, time cost: 26.5348ms
--- PASS: TestCountWithAtomic (0.03s)
PASS
ok      go-test 0.235s

多次测试后,从性能对比看:原子操作 > mutex > channel,三者都可以保证并发的安全性,但在性能上,mutex 也没有那么差,并且比 channel 很很多,原子操作通过 cpu操作的原子性,实现无锁,但主要适合于一些单值的比较增减,对于操作序列来看,适合 mutex 及 channel,由于 golang 本身的互斥锁有一定自旋特性,对比单纯的公平锁还是有一定提升,所以个人认为 mutex 不一定比 channel 差。

标签:wg,cnt,numsWorkers,sync,golang,mutex,time,var,channel
From: https://www.cnblogs.com/davis12/p/18320231

相关文章

  • 掌握时间与空间:深入探讨Golang中的时间戳与时区转换
    时间是我们生活的基石,而在计算机科学中,时间处理显得尤为重要。尤其是当你在处理分布式系统、跨时区应用和全球服务时,时间和时区的管理变得不可或缺。在这篇文章中,我们将以幽默和深入的方式探讨Golang中的时间戳与时区转换。时间的基本概念时间戳时间戳(Timestamp)是指从1970年1月......
  • netty入门-4 Channel与ChannelFuture
    Channel基本类似于NIO中的Channel概念。作为读写数据的通道。常见方法close()可以用来关闭channelcloseFuture()用来处理channel的关闭sync方法作用是同步等待channel关闭而addListener方法是异步等待channel关闭pipeline()方法添加处理器write()方法......
  • 从源码角度详解Golang调度GMP
    文章目录从源码角度详解Golang调度GMP1.1调度器的三个抽象概念:G、M、P1.2调度的大致轮廓2.进程启动时都做了什么2.1runtime.osinit(SB)方法针对系统环境的初始化2.2runtime.schedinit(SB)调度相关的一些初始化2.3runtime·mainPC(SB)启动监控任务2.4......
  • golang 构建Web服务器
    main.gopackagemainimport("fmt" "log" "net/http")funcloggingMiddleware(nexthttp.Handler)http.Handler{ returnhttp.HandlerFunc(func(whttp.ResponseWriter,r*http.Request){ log.Printf("%s%s\n"......
  • Golang异步编程方式和技巧
    Golang异步编程方式和技巧原创 腾讯程序员 腾讯技术工程  2024年04月23日18:00 广东 12人听过Golang基于多线程、协程实现,与生俱来适合异步编程,当我们遇到那种需要批量处理且耗时的操作时,传统的线性执行就显得吃力,这时就会想到异步并行处理。下面介绍一些异步......
  • 【Golang 面试基础题】每日 5 题(三)
    ✍个人博客:Pandaconda-CSDN博客......
  • 深入探究 Golang 反射:功能与原理及应用
    Go出于通用性的考量,提供了反射这一功能。借助反射功能,我们可以实现通用性更强的函数,传入任意的参数,在函数内通过反射动态调用参数对象的方法并访问它的属性。举例来说,下面的bridge接口为了支持灵活调用任意函数,在运行时根据传入参数funcPtr,通过反射动态调用funcPtr指向的具体......
  • golang 值接收者和指针接收者
    代码示例先看个代码:packagemainimport( "fmt" "testing")funcTestValRecv(t*testing.T){ varaanimal=dog{"五红犬"} a.eat() a.sleep() varbanimal=&dog{"五黑犬"} b.eat() b.sleep()}funcTestPtrRecv(t*tes......
  • Golang:bytes 格式和解析数字字节值(10K、2M、3G等)
    Golang:bytes格式和解析数字字节值(10K、2M、3G等)原创吃个大西瓜CodingBigTree 2024年06月10日08:01北京图片 bytes格式和解析数字字节值(10K、2M、3G等) 文档 https://github.com/labstack/gommon/tree/master/bytes安装 gogetgithub.com/labstack/go......
  • 深入探究 Golang 反射:功能与原理及应用
    Hi亲爱的朋友们,我是k哥。今天,咱们来一同探讨下Golang反射。Go出于通用性的考量,提供了反射这一功能。借助反射功能,我们可以实现通用性更强的函数,传入任意的参数,在函数内通过反射动态调用参数对象的方法并访问它的属性。举例来说,下面的bridge接口为了支持灵活调用任意函数,在......