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

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

Go Concurrency:Chudnovky 的算法,比同步慢

Go Concurrency:Chudnovky 的算法,比同步慢

Go
呼喚遠方 2021-12-27 14:56:38
我最近在朋友的推薦下開始學習圍棋。到目前為止,我很喜歡它,但我寫了(我認為會是)輕量級并發力量的完美例子,并得到了令人驚訝的結果......所以我懷疑我做錯了什么,或者我是誤解 goroutine 的成本有多高。我希望這里的一些地鼠可以提供洞察力。我使用 goroutines 和簡單的同步執行在 Go 中編寫了 Chudnovsky 的算法。我假設,由于每個計算都獨立于其他計算,因此并發運行至少會快一點。注意:我在第 5 代 i7 上運行它,所以如果 goroutine 像我被告知的那樣多路復用到線程上,這應該是并發和并行的。 package mainimport (  "fmt"  "math"  "strconv"  "time")func main() {  var input string  var sum float64  var pi float64  c := make(chan float64)  fmt.Print("How many iterations? ")  fmt.Scanln(&input)  max,err := strconv.Atoi(input)  if err != nil {    panic("You did not enter a valid integer")  }  start := time.Now() //start timing execution of concurrent routine  for i := 0; i < max; i++ {    go chudnovskyConcurrent(i,c)  }  for i := 0; i < max; i++ {    sum += <-c  }  end := time.Now() //end of concurrent routine  fmt.Println("Duration of concurrent calculation: ",end.Sub(start))  pi = 1/(12*sum)  fmt.Println(pi)  start = time.Now() //start timing execution of syncronous routine  sum = 0  for i := 0; i < max; i++ {    sum += chudnovskySync(i)  }  end = time.Now() //end of syncronous routine  fmt.Println("Duration of synchronous calculation: ",end.Sub(start))  pi = 1/(12*sum)  fmt.Println(pi)}func chudnovskyConcurrent(i int, c chan<- float64) {  var numerator float64  var denominator float64  ifloat := float64(i)  iun := uint64(i)  numerator = math.Pow(-1, ifloat) * float64(factorial(6*iun)) * (545140134*ifloat+13591409)  denominator = float64(factorial(3*iun)) * math.Pow(float64(factorial(iun)),3) * math.Pow(math.Pow(640320,3),ifloat+0.5)  c <- numerator/denominator}func chudnovskySync(i int) (r float64) {  var numerator float64  var denominator float64  ifloat := float64(i)  iun := uint64(i)  numerator = math.Pow(-1, ifloat) * float64(factorial(6*iun)) * (545140134*ifloat+13591409)  denominator = float64(factorial(3*iun)) * math.Pow(float64(factorial(iun)),3) * math.Pow(math.Pow(640320,3),ifloat+0.5)  r = numerator/denominator  return}
查看完整描述

2 回答

?
森林海

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

您正在執行的計算太簡單了,無法在單獨的 goroutine 中進行每一項計算。與實際計算相比,您在運行時(創建 goroutine、多路復用、調度等)浪費的時間更多。您正在嘗試做的更適合 GPU,例如,在那里您擁有大量并行執行單元,可以在瞬間完成這些簡單的計算。但是你需要其他語言和 API 來做到這一點。


您可以做的是為每個硬件執行線程創建軟件執行線程。您想將max變量分成大塊并并行執行。這是一個非常簡單的例子,只是為了說明這個想法:


package main


import (

  "fmt"

  "math"

  "strconv"

  "time"

  "runtime"

)


func main() {

  var input string

  var sum float64

  var pi float64

  c := make(chan float64, runtime.GOMAXPROCS(-1))

  fmt.Print("How many iterations? ")

  fmt.Scanln(&input)

  max,err := strconv.Atoi(input)


  if err != nil {

    panic("You did not enter a valid integer")

  }

  start := time.Now() //start timing execution of concurrent routine


  for i := 0; i < runtime.GOMAXPROCS(-1); i++ {

    go func(i int){

      var sum float64

      for j := 0; j < max/runtime.GOMAXPROCS(-1); j++  {

        sum += chudnovskySync(j + i*max/runtime.GOMAXPROCS(-1))

      }

      c <- sum

    }(i)

  }


  for i := 0; i < runtime.GOMAXPROCS(-1); i++ {

    sum += <-c

  }

  end := time.Now() //end of concurrent routine

  fmt.Println("Duration of concurrent calculation: ",end.Sub(start))

  pi = 1/(12*sum)

  fmt.Println(pi)


  start = time.Now() //start timing execution of syncronous routine

  sum = 0

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

    sum += chudnovskySync(i)

  }

  end = time.Now() //end of syncronous routine

  fmt.Println("Duration of synchronous calculation: ",end.Sub(start))

  pi = 1/(12*sum)

  fmt.Println(pi)

}


func chudnovskySync(i int) (r float64) {

  var numerator float64

  var denominator float64

  ifloat := float64(i)

  iun := uint64(i)

  numerator = math.Pow(-1, ifloat) * float64(factorial(6*iun)) * (545140134*ifloat+13591409)

  denominator = float64(factorial(3*iun)) * math.Pow(float64(factorial(iun)),3) * math.Pow(math.Pow(640320,3),ifloat+0.5)

  r = numerator/denominator

  return

}


func factorial(n uint64) (res uint64) {

  if ( n > 0 ) {

    res = n * factorial(n-1)

    return res

  }


  return 1

}

這是結果


$ go version

go version go1.5.2 windows/amd64


$ go run main.go

GOMAXPROCS = 4

How many iterations? 10000

Duration of concurrent calculation:  932.8916ms

NaN

Duration of synchronous calculation:  2.0639744s

NaN 


查看完整回答
反對 回復 2021-12-27
?
守著一只汪

TA貢獻1872條經驗 獲得超4個贊

我同意,您的計算沒有做足夠的處理來克服擁有多個 goroutine 的開銷。只是為了好玩,在返回結果之前,我修改了您的代碼以進行多次計算(1000、10000、100000、1000000)。我在四核 Xeon 上運行的 Mac OS X Yosemite 下運行了這個(20 次迭代),并且如您所料,同步版本的時間大約是并行版本的四倍。

我注意到的一件有趣的事情是,在大量重復的情況下,同步版本的時間實際上是并行版本的四倍多。我猜這與 Intel 的超線程架構有關,該架構允許在每個內核中實現某種程度的并行性,但我不確定這一點。


查看完整回答
反對 回復 2021-12-27
  • 2 回答
  • 0 關注
  • 194 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

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

幫助反饋 APP下載

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

公眾號

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