web-dev-qa-db-ja.com

golangでの並列処理

次のコードがあるとします:

package main

import (
    "fmt"
    "math/Rand"
    "time"
)

func main() {
    for i := 0; i < 3; i++ {
        go f(i)
    }

    // prevent main from exiting immediately
    var input string
    fmt.Scanln(&input)
}

func f(n int) {
    for i := 0; i < 10; i++ {
        dowork(n, i)
        amt := time.Duration(Rand.Intn(250))
        time.Sleep(time.Millisecond * amt)
    }
}

func dowork(goroutine, loopindex int) {
    // simulate work
    time.Sleep(time.Second * time.Duration(5))
    fmt.Printf("gr[%d]: i=%d\n", goroutine, loopindex)
}

「dowork」関数が並行して実行されると想定できますか?

これは、並列処理を実現する正しい方法ですか、それとも、各ルーチンにチャネルと個別の「dowork」ワーカーを使用する方が良いですか?

9
wilsonfiifi

コードは同時に実行されますが、並列には実行されません。 GOMAXPROCS;を設定することで、並列に実行できます。良い要約については、記事 https://www.ardanlabs.com/blog/2014/01/concurrency-goroutines-and-gomaxprocs.html を参照してください。

ここで何を達成しようとしているのかは明確ではありませんが、私にとって並行性を達成するための完全に有効な方法のように見えます。

17
Evan

GOMAXPROCSについては、Go 1.5のリリースドキュメントで確認できます。

デフォルトでは、Goプログラムは、GOMAXPROCSを使用可能なコア数に設定して実行されます。以前のリリースでは、デフォルトは1でした。

main関数がすぐに終了しないようにするために、WaitGroupWait関数を利用できます。

このユーティリティ関数は、関数のグループを並列化するために作成しました。

import "sync"

// Parallelize parallelizes the function calls
func Parallelize(functions ...func()) {
    var waitGroup sync.WaitGroup
    waitGroup.Add(len(functions))

    defer waitGroup.Wait()

    for _, function := range functions {
        go func(copy func()) {
            defer waitGroup.Done()
            copy()
        }(function)
    }
}

あなたの場合、私たちはこれを行うことができます

func1 := func() {
    f(0)
}

func2 = func() {
    f(1)
}

func3 = func() {
    f(2)
}

Parallelize(func1, func2, func3)

Parallelize関数を使用したい場合は、ここで見つけることができます https://github.com/shomali11/util

11
Raed Shomali

これは私が始めたときに私を助けました。

    package main

    import "fmt"

    func put(number chan<- int, count int) {
        i := 0
        for ; i <= (5 * count); i++ {
            number <- i
        }
        number <- -1
    }

    func subs(number chan<- int) {
        i := 10
        for ; i <= 19; i++ {
            number <- i
        }
    }

    func main() {
        channel1 := make(chan int)
        channel2 := make(chan int)
        done := 0
        sum := 0

        go subs(channel2)
        go put(channel1, 1)
        go put(channel1, 2)
        go put(channel1, 3)
        go put(channel1, 4)
        go put(channel1, 5)

        for done != 5 {
            select {
            case elem := <-channel1:
                if elem < 0 {
                    done++
                } else {
                    sum += elem
                    fmt.Println(sum)
                }
            case sub := <-channel2:
                sum -= sub
                fmt.Printf("atimta : %d\n", sub)
                fmt.Println(sum)
            }
        }
        close(channel1)
        close(channel2)
    }

「従来のクラスターベースのシステム(スーパーコンピューターなど)は、MPIを使用してプロセッサー間で並列実行を採用しています。MPIは、異なるプロセッサー上のオペレーティングシステムインスタンスで実行されるプロセス間の通信インターフェイスです。サポートしていません。スケジューリングなどの他のプロセス操作(さらに複雑になるリスクがあります。MPIプロセスはオペレーティングシステムによって実行されるため、1つのプロセッサで複数のMPIプロセスまたは単一のMPIプロセスは複数のスレッドを実行することもできます!) "

0
Wolfie

f()は同時に実行されますが、多くのdowork()は各f()内で順次実行されます。 stdinで待機することも、ルーチンの実行が完了したことを確認する正しい方法ではありません。 f()の終了時に、各f()trueをプッシュするチャネルを起動する必要があります。 main()の最後に、チャネル上でn個のtrueを待つ必要があります。 nは、スピンアップしたf()の数です。

0