golang 实现并发求和


Posted in Golang onMay 08, 2021

使用golang并发求和,作为对golang并发的一个练习.

为了验证结果的正确性,要给出最传统的版本:

func sum1(data []int) int {
 s := 0
 l := len(data)
 for i := 0; i < l; i++ {
  s += data[i]
 }
 return s
}

第二种方法

使用N个goroutine, 然后将N个分段的和写入N个channel中:

func sum2(data []int) int {
 s := 0
 l := len(data)
 const N = 5
 seg := l / N
 var chs [N]<-chan int
 for i := 0; i < N; i++ {
  chs[i] = worker(data[i*seg : (i+1)*seg])
 }
 for i := 0; i < N; i++ {
  s += <-chs[i]
 }
 return s
}
func worker(s []int) <-chan int {
 out := make(chan int)
 go func() {
  length := len(s)
  sum := 0
  for i := 0; i < length; i++ {
   sum += s[i]
  }
  out <- sum
 }()
 return out
}

对于一个求和的任务来说,用worker这种“模式”可能 太过麻烦,

看第三种

直接一个函数写出来:

func sum3(data []int) int {
 s := 0
 l := len(data)
 const N = 5
 seg := l / N
 var mu sync.Mutex
 var wg sync.WaitGroup
 wg.Add(N) // 直接加N个
 for i := 0; i < N; i++ {
  go func(ii int) {
   tmpS := data[ii*seg : (ii+1)*seg]
   ll := len(tmpS)
   mu.Lock()
   for i := 0; i < ll; i++ {
    s += tmpS[i]
   }
   mu.Unlock()
   wg.Done() // 一个goroutine运行完
  }(i)
 }
 wg.Wait() // 等N个goroutine都运行完
 return s
}

注意sum3要在读写s的地方加锁,因为s可能被多个goroutine并发读写。

最后一种方法有data race问题

不过运行结果是对的,看一下思路:

var sum4Tmp int
var sum4mu sync.Mutex
// 这个有data race问题,可以用WaitGroup改,只是提供一种思路
func sum4(data []int) int {
 //s := 0
 l := len(data)
 const N = 5
 seg := l / N
 for i := 0; i < N; i++ {
  go subsum4(data[i*seg : (i+1)*seg])
 }
 // 这里是>1,因为要排除main
 // 这种方法不可靠,只是一种思路
 for runtime.NumGoroutine() > 1 {
 }
 // go run -race sum.go会报data race问题
 // main goroutine对它读
 // 别的goroutine会对它写(go subsum4)
 return sum4Tmp
}
func subsum4(s []int) {
 length := len(s)
 sum := 0
 sum4mu.Lock()
 for i := 0; i < length; i++ {
  sum += s[i]
 }
 sum4Tmp = sum4Tmp + sum
 defer sum4mu.Unlock()
}

最后测试如下:

首先创建一个slice, 放1e8(1亿)个整数(范围[0,10))进去,

然后用4种方法进行计算

func calcTime(f func([]int) int, arr []int, tag string) {
 t1 := time.Now().UnixNano()
 s := f(arr)
 t2 := time.Now().UnixNano() - t1
 fmt.Printf("%15s: time: %d, sum: %d\n", tag, t2, s)
}
func main() {
 const MAX = 1e8 // 1亿
 arr := make([]int, MAX)
 for i := 0; i < MAX; i++ {
  arr[i] = rand.Intn(10)
 }
 calcTime(sum1, arr, "for")
 calcTime(sum2, arr, "worker")
 calcTime(sum3, arr, "WaitGroup")
 calcTime(sum4, arr, "NumGoroutine")
}

我的笔记本输出结果:

for: time: 61834200, sum: 450032946

worker: time: 51861100, sum: 450032946

WaitGroup: time: 153628200, sum: 450032946

NumGoroutine: time: 63791300, sum: 450032946

欢迎补充指正!

补充:Golang并发求和(竞争而非分段)

举例

如果要求2个goroutine并发完成1到100的和而不是分段的情况如何解决呢?

解决方案:

var wg sync.WaitGroup
var ch chan int32
var receiveCh chan int32
func add(){
	var sum int32
	sum = 0
	Loop:
	for {
		select {
		case val, ok := <-ch:
			if ok {
				atomic.AddInt32(&sum, val)
			} else {
				break Loop
			}
		}
	}
	receiveCh <- sum
	wg.Done()
}
func main() {
	wg.Add(3)
	ch = make(chan int32)
	receiveCh = make(chan int32, 2)
	go func(){
		for i := 1; i <= 100; i++{
			n := i //避免数据竞争
			ch <- int32(n) 
		}
		close(ch)
		wg.Done()
	}()
	go add()
	go add()
	wg.Wait()
	close(receiveCh)
	var sum int32
	sum = 0
	for res := range receiveCh{
		sum += res
	}
	fmt.Println("sum:",sum)
}

以上为个人经验,希望能给大家一个参考,也希望大家多多支持三水点靠木。如有错误或未考虑完全的地方,望不吝赐教。

Golang 相关文章推荐
win10下go mod配置方式
Apr 25 Golang
go语言中切片与内存复制 memcpy 的实现操作
Apr 27 Golang
golang import自定义包方式
Apr 29 Golang
解决go在函数退出后子协程的退出问题
Apr 30 Golang
Go标准容器之Ring的使用说明
May 05 Golang
go xorm框架的使用
May 22 Golang
详解Go语言Slice作为函数参数的使用
Jul 02 Golang
Go 中的空白标识符下划线
Mar 25 Golang
golang三种设计模式之简单工厂、方法工厂和抽象工厂
Apr 10 Golang
golang的文件创建及读写操作
Apr 14 Golang
Golang日志包的使用
Apr 20 Golang
Golang 结构体数据集合
Apr 22 Golang
golang中的并发和并行
May 08 #Golang
关于golang高并发的实现与注意事项说明
May 08 #Golang
基于Golang 高并发问题的解决方案
May 08 #Golang
使用golang编写一个并发工作队列
May 08 #Golang
Go 在 MongoDB 中常用查询与修改的操作
May 07 #Golang
golang 实现时间戳和时间的转化
May 07 #Golang
Golang Gob编码(gob包的使用详解)
May 07 #Golang
You might like
php mysql数据库操作分页类
2008/06/04 PHP
php定时计划任务的实现方法详解
2013/06/06 PHP
通过curl模拟post和get方式提交的表单类
2014/04/23 PHP
PHP中mysql_field_type()函数用法
2014/11/24 PHP
php自动载入类用法实例分析
2016/06/24 PHP
js removeChild 障眼法 可能出现的错误
2009/10/06 Javascript
jquery iframe操作详细解析
2013/11/20 Javascript
js限制checkbox选中个数以限制六个为例
2014/07/15 Javascript
angularjs指令中的compile与link函数详解
2014/12/06 Javascript
jQuery获取checkboxlist的value值的方法
2015/09/27 Javascript
jquery实现静态搜索功能(可输入搜索文字)
2017/03/28 jQuery
详解VueJS 数据驱动和依赖追踪分析
2017/07/26 Javascript
JavaScript实现简单的双色球(实例讲解)
2017/07/31 Javascript
vue-scroller记录滚动位置的示例代码
2018/01/17 Javascript
javascript少儿编程关于返回值的函数内容
2018/05/27 Javascript
JS实现键值对遍历json数组功能示例
2018/05/30 Javascript
实例分析vue循环列表动态数据的处理方法
2018/09/28 Javascript
JS立即执行函数功能与用法分析
2019/01/15 Javascript
使用express获取微信小程序二维码小记
2019/05/21 Javascript
三步实现ionic3点击退出app程序
2019/09/17 Javascript
vue中destroyed方法的使用说明
2020/07/21 Javascript
Jupyter notebook远程访问服务器的方法
2018/05/24 Python
使用Python自动生成HTML的方法示例
2019/08/06 Python
CSS3实现跳动的动画效果
2016/09/12 HTML / CSS
HTML5的video标签的浏览器兼容性增强方案分享
2016/05/19 HTML / CSS
建筑自我鉴定
2013/10/19 职场文书
网络工程系信息安全技术专业大学生求职信
2013/10/22 职场文书
教师自荐信
2013/12/10 职场文书
警示教育活动总结
2014/05/05 职场文书
2014年连锁店圣诞节活动方案
2014/12/09 职场文书
企业培训简报范文
2015/07/20 职场文书
总经理年会致辞
2015/07/29 职场文书
谢师宴学生答谢词
2015/09/30 职场文书
2017元旦、春节期间廉洁自律承诺书
2016/03/25 职场文书
创业计划书之干洗店
2019/09/10 职场文书
python游戏开发之pygame实现接球小游戏
2022/04/22 Python