2019年9月12日木曜日

開発環境

並行コンピューティング技法 ―実践マルチコア/マルチスレッドプログラミング (Clay Breshears(著)、千住 治郎(翻訳)、オライリージャパン)の5章(スレッドライブラリ)、5.2(明示的スレッドライブラリ)、5.2.1(Pthread)をC言語(POSIXスレッド、Pthreadライブラリ、OpenMPライブラリ等)ではなくGo言語(go文、goroutine、channel等)で取り組んでみる。

コード

sample1_test.go

package main

import "fmt"

func ExamplePi1() {
 fmt.Printf("%.2f", pi1())
 // Output: 3.14
}

func ExamplePi2() {
 fmt.Printf("%.2f", pi2())
 // Output: 3.14
}

sample1.go

package main

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

func main() {
 t := time.Now().UnixNano()
 p1 := pi1()
 fmt.Printf(
  "逐次処理: %vミリ秒\n", (time.Now().UnixNano()-t)/int64(time.Millisecond))
 t = time.Now().UnixNano()
 p2 := pi2()
 fmt.Printf(
  "並行処理: %vミリ秒\n", (time.Now().UnixNano()-t)/int64(time.Millisecond))
 fmt.Println("逐次処理: π ≒", p1)
 fmt.Println("並行処理: π ≒", p2)
}

func pi1() float64 {
 const numRects = 10e8
 partialHeight := 0.0
 for i := 0; i < numRects; i++ {
  x := (float64(i) + 0.5) / numRects
  partialHeight += 4.0 / (1.0 + x*x)
 }
 return partialHeight * 1 / numRects
}

func pi2() float64 {
 const numRects = 10e8
 numCPU := runtime.NumCPU()
 areaChannel := make(chan float64, numCPU)
 var wg sync.WaitGroup
 for i := 0; i < numCPU; i++ {
  wg.Add(1)
  go func(i int) {
   defer wg.Done()
   partialHeight := 0.0
   for j := i; j < numRects; j += numCPU {
    x := (float64(j) + 0.5) / numRects
    partialHeight += 4.0 / (1.0 + x*x)
   }

   areaChannel <- partialHeight * 1 / numRects
  }(i)
 }
 go func() {
  wg.Wait()
  close(areaChannel)
 }()
 areaTotal := 0.0
 for area := range areaChannel {
  areaTotal += area
 }
 return areaTotal
}

入出力結果(Bash、cmd.exe(コマンドプロンプト)、Terminal)

$ go test
# _/Users/.../go/並行コンピューティング技法/ch5/sample1 [_/Users/.../go/並行コンピューティング技法/ch5/sample1.test]
./sample1_test.go:6:21: undefined: pi1
./sample1_test.go:11:21: undefined: pi2
FAIL _/Users/.../go/並行コンピューティング技法/ch5/sample1 [build failed]
$ go test
PASS
ok   _/Users/.../go/並行コンピューティング技法/ch5/sample1 3.356s
$ go run sample1.go
逐次処理: 2547ミリ秒
並行処理: 667ミリ秒
逐次処理: π ≒ 3.141592653589971
並行処理: π ≒ 3.141592653589768
$ 

並行処理の方が速いことを確認出来た。結果が違うのは、浮動小数点数の計算の順番が逐次処理と並行処理で異なる可能性があるから、その途中で丸め誤差が発生してるのかも。

syncパッケージの構造体MutexとそのLockメソッド、Unlockメソッドを使えばグローバル変数を使用した、より本著のC言語のコードに近く書けるけど、最初にチャンネルを利用したくなったから少し異なる書き方で書いてみた。どちらがGopherらしいのかはまだよく分かってない。

0 コメント:

コメントを投稿