V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
The Go Programming Language
http://golang.org/
Go Playground
Go Projects
Revel Web Framework
oscarzhao
V2EX  ›  Go 编程语言

golang 小程序,多核 CPU 均跑到 100%

  •  
  •   oscarzhao ·
    oscarzhao · 2015-09-25 15:10:43 +08:00 · 3515 次点击
    这是一个创建于 3346 天前的主题,其中的信息可能已经有所发展或是发生改变。
    package main
    
    import (
        "math/rand"
        "runtime"
    )
    
    func runOneCpu() {
        for {
            rand.Intn(10000000)
        }
    }
    func main() {
        cpunum := runtime.NumCPU()
        runtime.GOMAXPROCS(cpunum)
        for i := 0; i < cpunum; i += 1 {
            go runOneCpu()
        }
        for {
        }
    }
    

    另外,如果要把跑到特定的百分比,还没有想到怎么整

    15 条回复    2016-03-11 20:58:38 +08:00
    abcdabcd987
        1
    abcdabcd987  
       2015-09-25 15:17:48 +08:00
    就像软 PWM 一样,在很短的时间段里面交替满负载 /空闲,比如 70%时间满负载, 30%时间空闲,那么整体看起来就像是 70%的 CPU 占用率。

    BTW 还可以根据这个原理在任务管理器上画函数图像呢
    yuankui
        2
    yuankui  
       2015-09-25 15:33:47 +08:00
    优越性在哪里?
    nekoyaki
        3
    nekoyaki  
       2015-09-25 15:38:35 +08:00
    我拿 go1.4 编译,发现只跑到 75%。
    拿 go1.5.1 编译,发现跑到 50%。。。
    oscarzhao
        4
    oscarzhao  
    OP
       2015-09-25 15:48:00 +08:00
    @nekoyaki 我在 win10 上面跑,刚开始是 98%左右,后来只有 73%左右,不知道 windows 做了什么优化
    oscarzhao
        5
    oscarzhao  
    OP
       2015-09-25 15:49:45 +08:00
    @abcdabcd987 不错,回头试试
    JohnSmith
        6
    JohnSmith  
       2015-09-25 17:30:20 +08:00
    无线循环太吃资源了
    wwek
        7
    wwek  
       2015-09-25 17:41:28 +08:00
    OSX go1.5.1 75% 左右
    ysmood
        8
    ysmood  
       2015-09-25 17:53:22 +08:00
    https://github.com/ysmood/heater

    之前冬天写的一个项目,冷的时候跑下,笔记本立马就热起来了。
    sh4n3
        9
    sh4n3  
       2015-09-25 18:07:45 +08:00
    @abcdabcd987 哈哈哈,,一看就是做硬件出身的
    abcdabcd987
        10
    abcdabcd987  
       2015-09-25 18:36:04 +08:00
    @sh4n3 其实不是,只是以前玩过单片机 :-D
    zhuang
        11
    zhuang  
       2015-09-25 19:40:53 +08:00
    go 1.5 之前, GOMAXPROCS 默认为 1 。之后默认为核心数量。 go 1.5 重新实现了 goroutine “调度器”。

    由于 goroutine 是在 thread 的基础上进行复用的,所以最终在 cpu 核心上体现的占用率还取决于内核调度器的实现。
    CRVV
        12
    CRVV  
       2015-09-26 00:18:51 +08:00
    我印象里把所有核都完全跑满并不容易
    需要用 ORTHOS
    lichundian
        13
    lichundian  
       2015-09-26 16:25:44 +08:00   ❤️ 1
    @nekoyaki @zhuang @wwek @oscarzhao
    出现没有跑满 CPU 的原因是: rand.Intn()方法会调用一个全局对象的方法生成随机数,这个全局方法是有 lock 的,所以会出现 golang 的多个 goroutine 相互竞争, lock 的底层实现,我不是很清楚,但是“ lock 检测不让 CPU 满载”是高并发程序的基本原则。要想让其满载,应该使用 goroutine 独立的计算模块,最简单就是
    for {} .
    见: https://golang.org/src/math/rand/rand.go#L238
    238 func (r *lockedSource) Int63() (n int64) {
    239 r.lk.Lock()
    240 n = r.src.Int63()
    241 r.lk.Unlock()
    242 return
    243 }

    另外作者程序存在两个问题:
    1. main 线程调用的计算和其他线程调用的计算不一样, main 线程会占用 100%,而其他线程并不会满负载。其 CPU 的负载结果很难说是平均每个线程的负载情况。
    2. Golang 映射的 native 的线程数可以通过 runtime.GOMAXPROCS(cpunum)设置,实际运行中最大的线程数在此基础上+1 ,因为还有 gc 线程。作者为了测试 routineNum 满载,除了 main 线程外,应该再开启 routineNum-1 个 goroutine 。

    我做了两个测试,硬件配置: 2CPU, 4 cores per CPU; Golang 配置: runtime.GOMAXPROCS(8):
    1.
    func main() {
    routineNum, err := strconv.Atoi(os.Args(1))

    cpunum := runtime.NumCPU()
    runtime.GOMAXPROCS(cpunum)
    for i := 0; i < routineNum -1 ; i += 1 {
    go func() {
    for {
    rand.Intn(10000000)
    }
    }()
    }
    for {
    rand.Intn(10000000)
    }
    }
    以下是测试结果
    routineNum 1 2 3 4 5 6 7 8
    CPU 使用率 100% 120% 201% 210% 220% 240% 266% 290%
    #native thread 4 5 6 6 7 8 9 9

    2.
    func main() {
    routineNum, err := strconv.Atoi(os.Args(1))

    cpunum := runtime.NumCPU()
    runtime.GOMAXPROCS(cpunum)
    for i := 0; i < routineNum -1 ; i += 1 {
    go func() {
    for {
    // nothing
    }
    }()
    }
    for {
    // nothing
    }
    }
    routineNum 1 2 3 4 5 6 7 8
    CPU 使用率 100% 199% 299% 399% 496% 597% 697% 790%
    #native threads 4 4 5 6 7 8 9 9

    所以楼上说 Golang 没有跑到满负载是做了什么优化是错误的,另外不同版本之间的差别只是因为 lock 的性能差别导致;内核调度器的实现不会这么傻,在 core 处于 idle 的时候难道不将计算密集型的线程分配在上面?

    所以楼主想实现制定的运行百分比,就应该摒弃采用 rand 计算的方法。而采取独立的计算方法。例如 for 循环满足一定条件就睡觉,当然还得事先计算好一定时间内会计算多少条语句,编程之美第一道题就是这个,作者去脑补吧。^_^
    lichundian
        14
    lichundian  
       2015-09-26 16:26:46 +08:00
    limengwei
        15
    limengwei  
       2016-03-11 20:58:38 +08:00 via Android
    楼上大神😜
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   5180 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 27ms · UTC 09:21 · PVG 17:21 · LAX 01:21 · JFK 04:21
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.