尽管将列表分割成由各个 goroutine 处理的更小的块,为什么'moving_avg_concurrent2”的性能没有随着并发性的增加而提高?
为什么 moving_avg_concurrent2 的性能无法随着并发执行的增加而提升?
moving_avg_concurrent2 将列表拆分为较小的片段,并使用单个 goroutine 处理每个片段。出于某种原因(目前尚不清楚原因),由于某些原因,使用一个 goroutine 的该函数比 moving_avg_serial4 更快,但使用多个 goroutine 的性能开始比 moving_avg_serial4 差。
为什么 moving_avg_concurrent3 比 moving_avg_serial4 慢得多?
使用一个 goroutine 时,moving_avg_concurrent3 的性能比 moving_avg_serial4 差。虽然增加 num_goroutines 可以提高性能,但仍然比 moving_avg_serial4 差。
即使 goroutine 是轻量级的,它们也并非完全免费,是否可能产生的开销如此之大,以至于速度甚至低于 moving_avg_serial4?
是的,虽然 goroutine 比较轻量级,但它们并不是免费的。当使用多个 goroutine 时,启动、管理和调度这些 goroutine 的开销可能会超过提升的并行度获得的好处。
代码
函数:
// 返回包含输入移动平均值的列表(已提供,即未优化) func moving_avg_serial(input []float64, window_size int) []float64 { first_time := true var output = make([]float64, len(input)) if len(input) > 0 { var buffer = make([]float64, window_size) // 初始化缓冲区为 NaN for i := range buffer { buffer[i] = math.NaN() } for i, val := range input { old_val := buffer[int((math.Mod(float64(i), float64(window_size))))] buffer[int((math.Mod(float64(i), float64(window_size))))] = val if !NaN_in_slice(buffer) && first_time { sum := 0.0 for _, entry := range buffer { sum += entry } output[i] = sum / float64(window_size) first_time = false } else if i > 0 && !math.IsNaN(output[i-1]) && !NaN_in_slice(buffer) { output[i] = output[i-1] + (val-old_val)/float64(window_size) // 无循环的解决方案 } else { output[i] = math.NaN() } } } else { // 空输入 fmt.Println("moving_avg is panicking!") panic(fmt.Sprintf("%v", input)) } return output } // 返回包含输入移动平均值的列表 // 重新排列控制结构以利用短路求值 func moving_avg_serial4(input []float64, window_size int) []float64 { first_time := true var output = make([]float64, len(input)) if len(input) > 0 { var buffer = make([]float64, window_size) // 初始化缓冲区为 NaN for i := range buffer { buffer[i] = math.NaN() } for i := range input { // fmt.Printf("in mvg_avg4: i=%v\n", i) old_val := buffer[int((math.Mod(float64(i), float64(window_size))))] buffer[int((math.Mod(float64(i), float64(window_size))))] = input[i] if first_time && !NaN_in_slice(buffer) { sum := 0.0 for j := range buffer { sum += buffer[j] } output[i] = sum / float64(window_size) first_time = false } else if i > 0 && !math.IsNaN(output[i-1]) /* && !NaN_in_slice(buffer)*/ { output[i] = output[i-1] + (input[i]-old_val)/float64(window_size) // 无循环的解决方案 } else { output[i] = math.NaN() } } } else { // 空输入 fmt.Println("moving_avg is panicking!") panic(fmt.Sprintf("%v", input)) } return output } // 返回包含输入移动平均值的列表 // 将列表拆分为较小的片段以使用 goroutine,但不使用串行版本,即我们仅在开头具有 NaN,因此希望减少一些开销 // 仍然不能扩展(随着大小和 num_goroutines 的增加,性能下降) func moving_avg_concurrent2(input []float64, window_size, num_goroutines int) []float64 { var output = make([]float64, window_size-1, len(input)) for i := 0; i < window_size-1; i++ { output[i] = math.NaN() } if len(input) > 0 { num_items := len(input) - (window_size - 1) var barrier_wg sync.WaitGroup n := num_items / num_goroutines go_avg := make([][]float64, num_goroutines) for i := 0; i < num_goroutines; i++ { go_avg[i] = make([]float64, 0, num_goroutines) } for i := 0; i < num_goroutines; i++ { barrier_wg.Add(1) go func(go_id int) { defer barrier_wg.Done() // 计算边界 var start, stop int start = go_id*int(n) + (window_size - 1) // 开始索引 // 结束索引 if go_id != (num_goroutines - 1) { stop = start + n // 结束索引 } else { stop = num_items + (window_size - 1) // 结束索引 } loc_avg := moving_avg_serial4(input[start-(window_size-1):stop], window_size) loc_avg = make([]float64, stop-start) current_sum := 0.0 for i := start - (window_size - 1); i < start+1; i++ { current_sum += input[i] } loc_avg[0] = current_sum / float64(window_size) idx := 1 for i := start + 1; i < stop; i++ { loc_avg[idx] = loc_avg[idx-1] + (input[i]-input[i-(window_size)])/float64(window_size) idx++ } go_avg[go_id] = append(go_avg[go_id], loc_avg...) }(i) } barrier_wg.Wait() for i := 0; i < num_goroutines; i++ { output = append(output, go_avg[i]...) } } else { // 空输入 fmt.Println("moving_avg is panicking!") panic(fmt.Sprintf("%v", input)) } return output } // 返回包含输入移动平均值的列表 // 模式改变,我们选择主工作者模式并生成将由 goroutine 计算的每个窗口 func compute_window_avg(input, output []float64, start, end int) { sum := 0.0 size := end - start for _, val := range input[start:end] { sum += val } output[end-1] = sum / float64(size) } func moving_avg_concurrent3(input []float64, window_size, num_goroutines int) []float64 { var output = make([]float64, window_size-1, len(input)) for i := 0; i < window_size-1; i++ { output[i] = math.NaN() } if len(input) > 0 { num_windows := len(input) - (window_size - 1) var output = make([]float64, len(input)) for i := 0; i < window_size-1; i++ {
以上是尽管将列表分割成由各个 goroutine 处理的更小的块,为什么'moving_avg_concurrent2”的性能没有随着并发性的增加而提高?的详细内容。更多信息请关注PHP中文网其他相关文章!

热AI工具

Undresser.AI Undress
人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover
用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool
免费脱衣服图片

Clothoff.io
AI脱衣机

Video Face Swap
使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热门文章

热工具

记事本++7.3.1
好用且免费的代码编辑器

SublimeText3汉化版
中文版,非常好用

禅工作室 13.0.1
功能强大的PHP集成开发环境

Dreamweaver CS6
视觉化网页开发工具

SublimeText3 Mac版
神级代码编辑软件(SublimeText3)

OpenSSL,作为广泛应用于安全通信的开源库,提供了加密算法、密钥和证书管理等功能。然而,其历史版本中存在一些已知安全漏洞,其中一些危害极大。本文将重点介绍Debian系统中OpenSSL的常见漏洞及应对措施。DebianOpenSSL已知漏洞:OpenSSL曾出现过多个严重漏洞,例如:心脏出血漏洞(CVE-2014-0160):该漏洞影响OpenSSL1.0.1至1.0.1f以及1.0.2至1.0.2beta版本。攻击者可利用此漏洞未经授权读取服务器上的敏感信息,包括加密密钥等。

在BeegoORM框架下,如何指定模型关联的数据库?许多Beego项目需要同时操作多个数据库。当使用Beego...

后端学习路径:从前端转型到后端的探索之旅作为一名从前端开发转型的后端初学者,你已经有了nodejs的基础,...

Go语言中使用RedisStream实现消息队列时类型转换问题在使用Go语言与Redis...

GoLand中自定义结构体标签不显示怎么办?在使用GoLand进行Go语言开发时,很多开发者会遇到自定义结构体标签在�...

Go语言中用于浮点数运算的库介绍在Go语言(也称为Golang)中,进行浮点数的加减乘除运算时,如何确保精度是�...

Go爬虫Colly中的Queue线程问题探讨在使用Go语言的Colly爬虫库时,开发者常常会遇到关于线程和请求队列的问题。�...

本文介绍如何在Debian系统上配置MongoDB实现自动扩容,主要步骤包括MongoDB副本集的设置和磁盘空间监控。一、MongoDB安装首先,确保已在Debian系统上安装MongoDB。使用以下命令安装:sudoaptupdatesudoaptinstall-ymongodb-org二、配置MongoDB副本集MongoDB副本集确保高可用性和数据冗余,是实现自动扩容的基础。启动MongoDB服务:sudosystemctlstartmongodsudosys
