[go] 如何更好地组织这段Golang代码
[go] 如何更好地组织这段Golang代码 我有两个数组
arr1 包含100个元素的数组
arr2 包含1000000个元素的数组
如何遍历arr2并将每100个元素分配给第一个数组,并实现多线程处理?
请帮忙)
首先尝试在单个 goroutine 中解决问题。一旦你有了这段代码,我们可以讨论并帮助你实现并发。
除此之外,我不确定是否值得这样做,将这项工作分散到多个 goroutine 中可能比在单个 goroutine 中执行效率更低,因为 goroutine 会带来少量开销,而且数据必须在内存和 CPU 之间来回传输,这是通过共享数据总线进行的。
更多关于[go] 如何更好地组织这段Golang代码的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
并发写入单个文件不是一个好主意。
- 它会导致写入顺序错乱
- 甚至可能使写入的数据相互交错
因此可能会出现以下情况(简化示例):
Line 1
Line 2
Line 2
Line 1
LinLine 2
e 1
LiLine 1
ne 2
LiLinene 1
2
这是我想做的事情
https://play.golang.org/p/0r55y2HD3V-
我写了简单的代码,但数组中的值减少了,在arr2数组中会有1,000,000,000个值,我该如何实现一个类似的多线程代码,比如我指定100,就会有100个线程,或者有什么不同的方法?
谁能根据示例代码帮助我解决这种情况
这是一个没有任何磁盘访问、网络操作或其他会让goroutine等待(从而让其他goroutine有机会运行)的紧密循环。因此,能够同时工作的最大goroutine数量等于您拥有的(逻辑)核心数。您可以通过以下方式获取这个数字:
runtime.NumCPU()
在普通2核或4核CPU上,您或许可以并行运行这么多goroutine。然而,如果为了确保不同核心能看到相同的内存内容而需要在各级缓存之间来回传输数组,这可能会花费更长时间。
我爱你,谢谢你。不过我之前举例说只有2个数组,实际上我自己也没完全理解所有机制,但我觉得你的示例正是我需要的(取模运算)。
我的想法是,在每一行中我会将这样的数据写入一个大文件,每行包含从最后一个循环中获取的数据:
arr2 [i], arr1 [i% len (arr1)], arr0 [i% len (arr0)] ..
由于存在如此大量的循环,我实在不知道该如何应用多线程(更何况还要把所有内容写入文件)。
但从你的帖子中,我学到了如何轻松处理(取模运算)
或者用单线程执行这样的操作会更好吗?
你可以使用 Goroutine 和 Channel 来并行处理这种大规模数组的分配任务。以下是一个完整的示例,将 arr2 每 100 个元素分配给 arr1 的对应元素,并利用多线程加速处理:
package main
import (
"fmt"
"sync"
)
func main() {
// 初始化数组
arr1 := make([]int, 100)
arr2 := make([]int, 1000000)
// 填充示例数据(实际使用时替换为你的数据)
for i := range arr2 {
arr2[i] = i
}
// 创建等待组和互斥锁
var wg sync.WaitGroup
var mu sync.Mutex
// 计算每个 Goroutine 处理的元素数量
chunkSize := 100
totalChunks := len(arr2) / chunkSize
// 启动 Goroutine 处理每个数据块
for chunk := 0; chunk < totalChunks; chunk++ {
wg.Add(1)
go func(chunkIndex int) {
defer wg.Done()
start := chunkIndex * chunkSize
end := start + chunkSize
if end > len(arr2) {
end = len(arr2)
}
// 处理当前数据块
chunkData := arr2[start:end]
// 计算分配到 arr1 的哪个位置
arr1Index := chunkIndex % len(arr1)
// 使用互斥锁保护对 arr1 的写入
mu.Lock()
// 这里可以根据你的具体需求定义分配逻辑
// 示例:将数据块的和赋给 arr1 对应位置
sum := 0
for _, val := range chunkData {
sum += val
}
arr1[arr1Index] += sum
mu.Unlock()
}(chunk)
}
// 等待所有 Goroutine 完成
wg.Wait()
// 输出结果示例
fmt.Printf("处理完成,arr1 前10个元素: %v\n", arr1[:10])
}
如果你需要更细粒度的控制,这里是一个使用 Channel 的替代方案:
package main
import (
"fmt"
"sync"
)
func main() {
arr1 := make([]int, 100)
arr2 := make([]int, 1000000)
// 填充示例数据
for i := range arr2 {
arr2[i] = i
}
var wg sync.WaitGroup
var mu sync.Mutex
chunkSize := 100
totalChunks := len(arr2) / chunkSize
// 创建任务 Channel
jobs := make(chan int, totalChunks)
// 启动 Worker
numWorkers := 10
for w := 0; w < numWorkers; w++ {
wg.Add(1)
go worker(w, jobs, &wg, &mu, arr1, arr2, chunkSize)
}
// 发送任务
for chunk := 0; chunk < totalChunks; chunk++ {
jobs <- chunk
}
close(jobs)
wg.Wait()
fmt.Printf("处理完成,arr1 前10个元素: %v\n", arr1[:10])
}
func worker(id int, jobs <-chan int, wg *sync.WaitGroup, mu *sync.Mutex,
arr1 []int, arr2 []int, chunkSize int) {
defer wg.Done()
for chunkIndex := range jobs {
start := chunkIndex * chunkSize
end := start + chunkSize
if end > len(arr2) {
end = len(arr2)
}
chunkData := arr2[start:end]
arr1Index := chunkIndex % len(arr1)
mu.Lock()
sum := 0
for _, val := range chunkData {
sum += val
}
arr1[arr1Index] += sum
mu.Unlock()
}
}
关键点说明:
- 使用
sync.WaitGroup等待所有 Goroutine 完成 - 使用
sync.Mutex保护对共享数组arr1的并发访问 - 将大数组分割成 100 个元素的数据块进行处理
- 通过取模运算
chunkIndex % len(arr1)确定分配到arr1的哪个位置
根据你的具体分配逻辑需求,可以修改数据处理部分的代码。


