《7天学会Go并发编程》第一天 go并发实战初窥门径

 系列文章目录

《7天学会Go并发编程》第一天 go并发实战初窥门径_大锤爱编程的博客-CSDN博客😯编程就是手艺活,看了就要练,看了就要写。不写不练浪费时间撒。🚗🚗🚗🚗今天先搞起一个Go当中的并发编程处理。一、Go当中常用并发二、Go 并发案例基本使用三、个人总结https://blog.csdn.net/alike_u/article/details/124056852?spm=1001.2014.3001.5502

《7天学会Go并发编程》の第二天 写一个简单的Go并发程序以及Goroutine的使用_大锤爱编程的博客-CSDN博客一文学会go线程的常见应用https://blog.csdn.net/alike_u/article/details/124237576?spm=1001.2014.3001.5502

《7天学会Go并发编程》第三天 go的Mutex使用_大锤爱编程的博客-CSDN博客😯go语言并发编程中,简单经典好用的就是Mutex,也就是go语言中的互斥,适用于比较初阶的go并发编程。🚗🚗🚗文章里面会介绍Mutex的两个经典使用方法。目录一、go语言并发简介二、go语言并发小试牛刀2.1 原生态并发计数2.1 遇事不决,加把锁2.2 加锁慢又麻,原子操作好快省2.3channel,go并发灵魂三、总结一、Mutex是什么Mutex是go语言当中的互斥锁,作用是用来给临界区的数据加锁,保证一次只有一个goroutline可以对..https://blog.csdn.net/alike_u/article/details/124463044?spm=1001.2014.3001.5502

《7天学会Go并发编程》第四天 sync.Once和sync.WaitGroup学习应用实践_大锤爱编程的博客-CSDN博客😯并发编程当总是会遇到一些线程调度的问题。有A,B,C,D四个线程,需要确保在A,B,C执行结束后,再执行D线程。比如写一段Fan-In,多表融合的代码,A,B,C从独立的三表中抽取出数据,在线程D中进行融合。那么在这个过程中,如果ABC线程数据抽取未完成,D就开始进行数据融合,势必造成数据融合结果的缺失,不完整。 单线程的单次执行,也就是说这个线程只能执行一次。比如循环判断一个条件是否满足,满足以后执行单次执行,避免重复执行。例如金额的累加,判断累加值以后,不论成功与否...https://blog.csdn.net/alike_u/article/details/124569174?spm=1001.2014.3001.5502

《7天学会Go并发编程》第五天 go语言Context的应用和实现 go实现超时判断_大锤爱编程的博客-CSDN博客系列文章目录提示:这里可以添加系列文章的所有文章的目录,目录需要自己手动添加例如:第一章 Python 机器学习入门之pandas的使用提示:写完文章后,目录可以自动生成,如何生成可参考右边的帮助文档文章目录系列文章目录前言一、pandas是什么?二、使用步骤1.引入库2.读入数据总结前言提示:这里可以添加本文要记录的大概内容:例如:随着人工智能的不断发展,机器学习这门技术也越来越重要,很多人都开启了学习机器学习,本文就介绍了机器学习的https://blog.csdn.net/alike_u/article/details/124721223?spm=1001.2014.3001.5502

《7天学会Go并发编程》第六天 go语言Sync.cond的应用和实现 go实现多线程联合执行_大锤爱编程的博客-CSDN博客CSDN话题挑战赛第1期活动详情地址:CSDN参赛话题:大数据学习记录话题描述:大数据生态圈内的理念和技术实现,包括但不局限于大数据存储(数据湖、数据仓库、消息队列等)、大数据计算(离线批、实时流等)、大数据应用(报表可视化、OLAP应用、用户画像、智能搜索、智能推荐等)、大数据的调度(各类调度器)等方面;囊括开源社区(如Apache、CDH、HDP、等)大数据技术栈以及公有云(如AWS、阿里云、华为云、腾讯云、Microsoft Azure)大数据技术栈,这里是大数据的阵地,让各类大数据理念在此百家https://blog.csdn.net/alike_u/article/details/124677244?spm=1001.2014.3001.5502

《7天学会Go并发编程》第7天 go语言并发编程Atomic原子实战操作含ABA问题_大锤爱编程的博客-CSDN博客目录一、Atomic-原子操作简介二、🍻go语言Atomic源码分析和实战操作2.1🍺🍺🍺 Atomic 关键函数及其释义2.1 🍭🍭🍭atomic实战2.2 🍖🍖🍖atomic原子并发操作2.3 🍟🍟🍟任意数据结构的原子操作三、🍏🍏🍏总结原子操作其实和原子没有什么关系,主要借用的是原子不可分割的概念来强调说明这个操作也不可以被分割。🚗使用并发编程时需要解决的就是临界区(公共资源的修改)问题,抽象的数据操作行为是RAW,WAR,WAW。🥤🥤🥤体现在具体编码过程中,就是...https://blog.csdn.net/alike_u/article/details/125349003?spm=1001.2014.3001.5502

😯编程就是手艺活,看了就要练,看了就要写。不写不练浪费时间撒。

🚗🚗🚗🚗今天先搞起一个Go并发技术错误,并使用一些常见方法实现正确并发编程。

目录

一、go语言并发简介

二、go语言并发小试牛刀

2.1 原生态并发计数

2.1 遇事不决,加把锁

2.2 加锁慢又麻,原子操作好快省

2.3 channel,go并发灵魂

三、总结


一、go语言并发简介

并发编程的目的主要利用多核CPU并发执行,提升程序计算性能。使用多核CPU带来了一个挑战就是,每一个CPU都有自己的缓存,CPU执行运算时,都是把数据先加载到自己的缓存中使用,加载过程中,或者计算过程中,其他CPU已经对这个变量进行了修改,导致自己没办法拿到最新的数据计算。

简单的概括就是:🚗使用并发编程时,不可避免的就是临界区(公共资源的修改),抽象的数据操作行为是RAW,WAR,WAW。🥤🥤🥤

go语言为其线程创造了一个独特名字:goroutine。所有goroutline都使用同一块内存,所以goroutine当中使用的数据都必须要加锁使用,否则就会出现数据冲突🦴🦴🦴。

这样:

二、🍻go语言并发小试牛刀

在第一天里面,主要是初步了解go当中的并发工具,以及并发编程应该是什么样的一个感观认识。

2.1🍺🍺🍺 原生态并发计数

  代码exam3实现的是并发开启十个线程计数,每个线程分别计数10次,正确的计数结果应该是1000次。

func exam1() {
	group := sync.WaitGroup{}
	count := 0
	for i := 0; i < 100; i++ {
		group.Add(1)
		go func() {
			for i := 0; i < 10; i++ {
				count++
			}
			group.Done()
		}()
	}
	group.Wait()
	fmt.Printf("100 goroutine count 10 times  is %v times", count)
}

实际结果却是:  990次

这就奇怪了,不应该呀。应该是1000的。


 

值对不上的原因就是:

 当go开启一个goroutine的时候,每一个goroutine都对count变量进行修改。👾没有加锁! 

原因分析:

下面就使用go -race检一下哪里有冲突。

哦豁,go -race检查以后,居然是一个正确的结果!!为啥呢

从下文前两行,可以看出0x00c00012e058 这个地址发生了RAW操作。虽然这个结果最后是1000次,这是操作系统自身缓存的原因优化出来的结果,属于运气。goroutine内部计数次数变化的话,count总值就不对了!

WARNING: DATA RACE
Read at 0x00c00012e058 by goroutine 8:
  main.exam1.func1()
       /MyOwnExercise.go:51 +0x4c

Previous write at 0x00c00012e058 by goroutine 7:
  main.exam1.func1()
       /MyOwnExercise.go:51 +0x64

Goroutine 8 (running) created at:
  main.exam1()
       /MyOwnExercise.go:49 +0xf3
  main.main()
       /MyOwnExercise.go:14 +0x36

Goroutine 7 (finished) created at:
  main.exam1()
       /MyOwnExercise.go:49 +0xf3
  main.main()
       /MyOwnExercise.go:14 +0x36
==================
100 goroutine count 10 times  is 1000 timesFound 1 data race(s)
exit status 66

2.1 🍭🍭🍭遇事不决,加把锁

加锁,使用mutex解决线程并发问题 。加锁通俗的说就是对资源上锁,拿到钥匙的人才能访问,控制住了钥匙,⚓️就能控制住访问顺序。

func exam2() {
	//增加锁
	mutex := sync.Mutex{}
	group := sync.WaitGroup{}
	count := 0
	for i := 0; i < 100; i++ {
		group.Add(1)
		go func( ) {
			//加锁
			mutex.Lock()
			for i := 0; i < 10000; i++ {
				count++
			}
			//解锁
			mutex.Unlock()
			group.Done()
		}()
	}
	group.Wait()
	fmt.Printf("100 goroutine count 1000 times  is %v times", count)
}

 执行结果:显然。正确答案,数据无冲突。

go run -race .\MyOwnExercise.go
100 goroutine count 1000 times  is 1000000 times

2.2 🍖🍖🍖加锁慢又麻,原子操作好快省

原理:就是每次对数据的操作,都不经过缓存,直接在数据地址上对数据进行操🌆作。

func atomicExam3() {
	group := sync.WaitGroup{}
	var count int32
	for i := 0; i < 100; i++ {
		group.Add(1)
		go func( ) {
			for i := 0; i < 10000; i++ {
				atomic.AddInt32(&count,1)
			}
			group.Done()
		}()
	}
	group.Wait()
	fmt.Printf("100 goroutine count 1000 times  is %v times", atomic.LoadInt32(&count))
}

 结论:那当然是正确了。博客里面怎么会有不对的答案

go run -race .\MyOwnExercise.go
100 goroutine count 1000 times  is 1000000 times

2.3 🍟🍟🍟channel,go并发灵魂

嗯,原理就是你发过来,我收着,就是一个半双工通信的模式。通过半双工🌠🌠,实现对修改数据的并发操作。

func channelExam3() {
	group := sync.WaitGroup{}
	resChann := make(chan int,1)
	resChann<-0
	for i := 0; i < 100; i++ {
		group.Add(1)
		go func( ) {
			for i := 0; i < 10000; i++ {
				i2 := <-resChann
				i2++
				resChann<-i2
			}
			group.Done()
		}()
	}
	group.Wait()
	fmt.Printf("100 goroutine count 1000 times  is %v times", <-resChann)
}

  执行结果:毫无意外,又是正确执行。

go run -race .\MyOwnExercise.go
100 goroutine count 1000 times  is 1000000 times

三、🍏🍏🍏总结

        今天介绍了一下,并发编程为什么会失败,为什么会有并发编程。如何通过加锁、原子操作、通道来分别实现并发次数。后续的文章中,会继续拓展、深化go并发编程原理和生产案例💪🏻⛽️~

🧧🧧🧧感谢诸位大佬的阅读,点个关注,收藏一下呗~

    

  • 5
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

大锤爱编程

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值