[go] 如何更好地组织这段Golang代码

[go] 如何更好地组织这段Golang代码 我有两个数组

arr1 包含100个元素的数组

arr2 包含1000000个元素的数组

如何遍历arr2并将每100个元素分配给第一个数组,并实现多线程处理?

请帮忙)

7 回复

首先尝试在单个 goroutine 中解决问题。一旦你有了这段代码,我们可以讨论并帮助你实现并发。

除此之外,我不确定是否值得这样做,将这项工作分散到多个 goroutine 中可能比在单个 goroutine 中执行效率更低,因为 goroutine 会带来少量开销,而且数据必须在内存和 CPU 之间来回传输,这是通过共享数据总线进行的。

更多关于[go] 如何更好地组织这段Golang代码的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


如果使用模运算,打印内容看起来会简单得多:

https://play.golang.org/p/YC50ZeJuwiC

但在你的第一篇帖子中,你说想从较小的切片初始化更大的切片,而且当时只有两个切片。现在你有三个了。

能否详细说明一下?

并发写入单个文件不是一个好主意。

  1. 它会导致写入顺序错乱
  2. 甚至可能使写入的数据相互交错

因此可能会出现以下情况(简化示例):

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 的哪个位置

根据你的具体分配逻辑需求,可以修改数据处理部分的代码。

回到顶部