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 相关文章推荐
golang 如何用反射reflect操作结构体
Apr 28 Golang
golang 定时任务方面time.Sleep和time.Tick的优劣对比分析
May 05 Golang
golang gopm get -g -v 无法获取第三方库的解决方案
May 05 Golang
golang中的并发和并行
May 08 Golang
Golang生成Excel文档的方法步骤
Jun 09 Golang
go goroutine 怎样进行错误处理
Jul 16 Golang
golang内置函数len的小技巧
Jul 25 Golang
Golang中channel的原理解读(推荐)
Oct 16 Golang
Go 语言中 20 个占位符的整理
Oct 16 Golang
golang使用map实现去除重复数组
Apr 14 Golang
GO语言字符串处理函数之处理Strings包
Apr 14 Golang
GO中sync包自由控制并发示例详解
Aug 05 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中计算程序运行时间的类代码
2012/11/03 PHP
Yii框架连接mongodb数据库的代码
2016/07/27 PHP
Prototype使用指南之base.js
2007/01/10 Javascript
JavaScript 对象、函数和继承
2009/07/07 Javascript
jQuery之折叠面板的深入解析
2013/06/19 Javascript
JQuery打造省市下拉框联动效果
2014/05/18 Javascript
推荐5 个常用的JavaScript调试技巧
2015/01/08 Javascript
javascript连续赋值问题
2015/07/08 Javascript
jQuery图片旋转插件jQueryRotate.js用法实例(附demo下载)
2016/01/21 Javascript
分享两段简单的JS代码防止SQL注入
2016/04/12 Javascript
JS中innerHTML和pasteHTML的区别实例分析
2016/06/22 Javascript
微信小程序 弹窗自定义实例代码
2017/03/08 Javascript
使用D3.js制作图表详解
2017/08/13 Javascript
jQuery Datatable 多个查询条件自定义提交事件(推荐)
2017/08/24 jQuery
Vue2.0实现组件数据的双向绑定问题
2018/03/06 Javascript
vue.js 嵌套循环、if判断、动态删除的实例
2018/03/07 Javascript
webpack热模块替换(HMR)/热更新的方法
2018/04/05 Javascript
Vue不能检测到Object/Array更新的情况的解决
2018/06/26 Javascript
JS 实现获取验证码 倒计时功能
2018/10/29 Javascript
NodeJS实现一个聊天室功能
2019/11/25 NodeJs
JS实现秒杀倒计时特效
2020/01/02 Javascript
[02:26]2018DOTA2亚洲邀请赛赛前采访-Newbee篇
2018/04/03 DOTA
[01:05:07]DOTA2-DPC中国联赛 正赛 DLG vs Dragon BO3 第一场2月1日
2021/03/11 DOTA
解决DataFrame排序sort的问题
2018/06/07 Python
python中的句柄操作的方法示例
2019/06/20 Python
对python中的os.getpid()和os.fork()函数详解
2019/08/08 Python
Python2.7:使用Pyhook模块监听鼠标键盘事件-获取坐标实例
2020/03/14 Python
Python semaphore evevt生产者消费者模型原理解析
2020/03/18 Python
python输出国际象棋棋盘的实例分享
2020/11/26 Python
苏宁红孩子母婴商城:redbaby
2017/02/12 全球购物
毕业生医学检验求职信
2013/10/16 职场文书
高中生学习计划书
2014/09/15 职场文书
2014年“向国旗敬礼”网上签名寄语活动方案
2014/09/27 职场文书
师范生免费教育协议书范本
2014/10/09 职场文书
解除同居协议书
2015/01/29 职场文书
2015年求职自荐信范文
2015/03/04 职场文书