Golang如何高效利用多核与多线程

Golang如何高效利用多核与多线程 大家好,

我有一台配备64核/128线程的Threadripper Pro处理器。目前我的脚本仅利用了部分核心,而让其余核心处于空闲状态。有没有什么方法可以完全榨干CPU的性能?

谢谢。

4 回复

我们能看看代码吗?

更多关于Golang如何高效利用多核与多线程的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


目前我的脚本只利用了核心,而让其余部分闲置

你能澄清一下你这是什么意思吗?

抱歉。我有128个虚拟处理器,但它只使用了64个。

Screenshot 2021-07-27 113858

在Go中充分利用多核的关键在于合理使用goroutine和并行处理。以下是一些高效利用多核CPU的技术方案:

1. 设置GOMAXPROCS

默认情况下Go会使用所有可用CPU核心,但可以通过以下方式显式设置:

runtime.GOMAXPROCS(128) // 设置为线程数

2. 使用Worker Pool模式

避免创建过多goroutine,使用固定数量的worker处理任务:

package main

import (
    "fmt"
    "runtime"
    "sync"
)

func worker(id int, jobs <-chan int, results chan<- int, wg *sync.WaitGroup) {
    defer wg.Done()
    for job := range jobs {
        // 执行CPU密集型计算
        result := job * 2
        results <- result
    }
}

func main() {
    numWorkers := 128 // 与线程数匹配
    numJobs := 10000
    
    jobs := make(chan int, numJobs)
    results := make(chan int, numJobs)
    var wg sync.WaitGroup
    
    // 启动worker
    for w := 1; w <= numWorkers; w++ {
        wg.Add(1)
        go worker(w, jobs, results, &wg)
    }
    
    // 分发任务
    for j := 1; j <= numJobs; j++ {
        jobs <- j
    }
    close(jobs)
    
    // 等待所有worker完成
    wg.Wait()
    close(results)
}

3. 使用sync.Map进行并行处理

package main

import (
    "sync"
    "time"
)

func processData(data []int) map[int]int {
    var m sync.Map
    var wg sync.WaitGroup
    
    for _, value := range data {
        wg.Add(1)
        go func(v int) {
            defer wg.Done()
            // CPU密集型计算
            result := v * v
            m.Store(v, result)
        }(value)
    }
    
    wg.Wait()
    
    // 转换回普通map
    result := make(map[int]int)
    m.Range(func(key, value interface{}) bool {
        result[key.(int)] = value.(int)
        return true
    })
    
    return result
}

4. 使用并行算法库

package main

import (
    "github.com/golang/sync/errgroup"
    "golang.org/x/sync/semaphore"
)

func parallelProcessing() {
    var g errgroup.Group
    sem := semaphore.NewWeighted(128) // 限制并发数
    
    for i := 0; i < 1000; i++ {
        g.Go(func() error {
            // 获取信号量
            if err := sem.Acquire(context.Background(), 1); err != nil {
                return err
            }
            defer sem.Release(1)
            
            // 执行计算
            heavyComputation()
            return nil
        })
    }
    
    if err := g.Wait(); err != nil {
        panic(err)
    }
}

5. 使用runtime包监控CPU使用

package main

import (
    "fmt"
    "runtime"
    "time"
)

func monitorCPU() {
    go func() {
        for {
            var m runtime.MemStats
            runtime.ReadMemStats(&m)
            fmt.Printf("Goroutines: %d, CPUs: %d\n", 
                runtime.NumGoroutine(), 
                runtime.NumCPU())
            time.Sleep(time.Second)
        }
    }()
}

6. 使用pprof分析性能

package main

import (
    "net/http"
    _ "net/http/pprof"
)

func main() {
    // 启动pprof服务器
    go func() {
        http.ListenAndServe("localhost:6060", nil)
    }()
    
    // 你的主程序逻辑
}

对于64核/128线程的Threadripper Pro,建议:

  1. 使用worker pool模式,worker数量设置为128
  2. 确保任务足够细粒度以充分利用所有核心
  3. 避免goroutine间的锁竞争
  4. 使用无锁数据结构如sync.Map
  5. 定期使用pprof分析CPU使用情况

通过以上方法,可以最大化利用Threadripper Pro的多核性能。

回到顶部