亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

Golang 中的并發積分計算

Golang 中的并發積分計算

Go
紅顏莎娜 2022-03-02 13:15:03
我嘗試同時計算積分,但我的程序最終比使用普通 for 循環計算積分要慢。我究竟做錯了什么?package mainimport (    "fmt"    "math"    "sync"    "time")type Result struct {    result float64    lock sync.RWMutex}var wg sync.WaitGroupvar result Resultfunc main() {    now := time.Now()    a := 0.0    b := 1.0    n := 100000.0    deltax := (b - a) / n    wg.Add(int(n))    for i := 0.0; i < n; i++ {        go f(a, deltax, i)    }    wg.Wait()    fmt.Println(deltax * result.result)    fmt.Println(time.Now().Sub(now))}func f(a float64, deltax float64, i float64) {    fx := math.Sqrt(a + deltax * (i + 0.5))    result.lock.Lock()    result.result += fx    result.lock.Unlock()    wg.Done()}
查看完整描述

2 回答

?
汪汪一只貓

TA貢獻1898條經驗 獲得超8個贊

3-為了提高性能,您可以在不使用的情況下按 CPU 內核劃分任務lock sync.RWMutex:


+30x使用通道和 進行優化runtime.NumCPU(),這需要2ms2 核和993μs8 核,而您的示例代碼需要61ms2 核和40ms8 核:


請參閱此工作示例代碼和輸出:


package main


import (

    "fmt"

    "math"

    "runtime"

    "time"

)


func main() {

    nCPU := runtime.NumCPU()

    fmt.Println("nCPU =", nCPU)

    ch := make(chan float64, nCPU)

    startTime := time.Now()

    a := 0.0

    b := 1.0

    n := 100000.0 

    deltax := (b - a) / n


    stepPerCPU := n / float64(nCPU)

    for start := 0.0; start < n; {

        stop := start + stepPerCPU

        go f(start, stop, a, deltax, ch)

        start = stop

    }


    integral := 0.0

    for i := 0; i < nCPU; i++ {

        integral += <-ch

    }


    fmt.Println(time.Now().Sub(startTime))

    fmt.Println(deltax * integral)

}


func f(start, stop, a, deltax float64, ch chan float64) {

    result := 0.0

    for i := start; i < stop; i++ {

        result += math.Sqrt(a + deltax*(i+0.5))

    }

    ch <- result

}

2核輸出:


nCPU = 2

2.0001ms

0.6666666685900485

8核輸出:


nCPU = 8

993μs

0.6666666685900456

您的示例代碼,2 核輸出:


0.6666666685900424

61.0035ms

您的示例代碼,8 核輸出:


0.6666666685900415

40.9964ms

2-為了獲得良好的基準統計數據,請使用大量樣本(大 n):


正如您在此處看到的,使用 2 個內核需要2 個內核,但在使用 1 個內核的同110ms一個 CPU 上,這需要: 215msn := 10000000.0


使用n := 10000000.0單個 goroutine,請參閱此工作示例代碼:


package main


import (

    "fmt"

    "math"

    "time"

)


func main() {

    now := time.Now()

    a := 0.0

    b := 1.0

    n := 10000000.0

    deltax := (b - a) / n

    result := 0.0

    for i := 0.0; i < n; i++ {

        result += math.Sqrt(a + deltax*(i+0.5))

    }

    fmt.Println(time.Now().Sub(now))

    fmt.Println(deltax * result)

}

輸出:


215.0123ms

0.6666666666685884

使用n := 10000000.0和 2 個 goroutine,請參閱此工作示例代碼:


package main


import (

    "fmt"

    "math"

    "runtime"

    "time"

)


func main() {

    nCPU := runtime.NumCPU()

    fmt.Println("nCPU =", nCPU)

    ch := make(chan float64, nCPU)

    startTime := time.Now()

    a := 0.0

    b := 1.0

    n := 10000000.0

    deltax := (b - a) / n


    stepPerCPU := n / float64(nCPU)

    for start := 0.0; start < n; {

        stop := start + stepPerCPU

        go f(start, stop, a, deltax, ch)

        start = stop

    }


    integral := 0.0

    for i := 0; i < nCPU; i++ {

        integral += <-ch

    }


    fmt.Println(time.Now().Sub(startTime))

    fmt.Println(deltax * integral)

}


func f(start, stop, a, deltax float64, ch chan float64) {

    result := 0.0

    for i := start; i < stop; i++ {

        result += math.Sqrt(a + deltax*(i+0.5))

    }

    ch <- result

}

輸出:


nCPU = 2

110.0063ms

0.6666666666686073

1- Goroutines 的數量有一個最佳點,從這一點開始,增加 Goroutines 的數量并不會減少程序執行時間:


在 2 核 CPU 上,使用以下代碼,結果是:


nCPU: 1,          2,          4,         8,           16

Time: 2.1601236s, 1.1220642s, 1.1060633s, 1.1140637s, 1.1380651s

正如你所看到的nCPU=1 ,nCPU=2減少量已經足夠大,但在此之后它并不多,所以nCPU=22 Cores CPU 是此示例代碼的最佳點,所以在這里使用 nCPU := runtime.NumCPU()就足夠了。


package main


import (

    "fmt"

    "math"

    "time"

)


func main() {

    nCPU := 2 //2.1601236s@1 1.1220642s@2 1.1060633s@4 1.1140637s@8 1.1380651s@16

    fmt.Println("nCPU =", nCPU)

    ch := make(chan float64, nCPU)

    startTime := time.Now()

    a := 0.0

    b := 1.0

    n := 100000000.0

    deltax := (b - a) / n


    stepPerCPU := n / float64(nCPU)

    for start := 0.0; start < n; {

        stop := start + stepPerCPU

        go f(start, stop, a, deltax, ch)

        start = stop

    }


    integral := 0.0

    for i := 0; i < nCPU; i++ {

        integral += <-ch

    }


    fmt.Println(time.Now().Sub(startTime))

    fmt.Println(deltax * integral)

}


func f(start, stop, a, deltax float64, ch chan float64) {

    result := 0.0

    for i := start; i < stop; i++ {

        result += math.Sqrt(a + deltax*(i+0.5))

    }

    ch <- result

}


查看完整回答
反對 回復 2022-03-02
?
拉風的咖菲貓

TA貢獻1995條經驗 獲得超2個贊

除非 goroutine 中的活動花費的時間比切換上下文、執行任務和使用互斥鎖更新值所需的時間多得多,否則串行執行會更快。


看一個稍微修改過的版本。我所做的只是在f()函數中添加 1 微秒的延遲。


package main


import (

    "fmt"

    "math"

    "sync"

    "time"

)


type Result struct {

    result float64

    lock   sync.RWMutex

}


var wg sync.WaitGroup

var result Result


func main() {

    fmt.Println("concurrent")

    concurrent()

    result.result = 0

    fmt.Println("serial")

    serial()

}


func concurrent() {

    now := time.Now()

    a := 0.0

    b := 1.0

    n := 100000.0

    deltax := (b - a) / n

    wg.Add(int(n))

    for i := 0.0; i < n; i++ {

        go f(a, deltax, i, true)

    }

    wg.Wait()

    fmt.Println(deltax * result.result)

    fmt.Println(time.Now().Sub(now))

}


func serial() {

    now := time.Now()

    a := 0.0

    b := 1.0

    n := 100000.0

    deltax := (b - a) / n

    for i := 0.0; i < n; i++ {

        f(a, deltax, i, false)

    }

    fmt.Println(deltax * result.result)

    fmt.Println(time.Now().Sub(now))

}


func f(a, deltax, i float64, concurrent bool) {

    time.Sleep(1 * time.Microsecond)

    fx := math.Sqrt(a + deltax*(i+0.5))

    if concurrent {

        result.lock.Lock()

        result.result += fx

        result.lock.Unlock()

        wg.Done()

    } else {

        result.result += fx

    }

}

加上延遲,結果如下(并發版本快很多):


concurrent

0.6666666685900424

624.914165ms


serial

0.6666666685900422

5.609195767s

事不宜遲:


concurrent

0.6666666685900428

50.771275ms


serial

0.6666666685900422

749.166μs

正如你所看到的,完成一項任務所花費的時間越長,如果可能的話,同時執行它就越有意義。


查看完整回答
反對 回復 2022-03-02
  • 2 回答
  • 0 關注
  • 176 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號