30


8

Goのマルチスレッドアプローチと、pthread、boost

thread、Java Threadsなどの他のアプローチとの違いは何ですか?

4 Answer


23


https://git.ustclug.org/zhsso/go/blob/fa3d86ca39f9d168f194b232538794bd09f887f3/doc/GoCourseDay3.pdf [3日目のチュートリアル] < - こちらからお読みください。

_ _ ゴルーチンは、必要に応じてシステムスレッドに多重化されます。 ゴルーチンがブロッキングシステムコールを実行するとき、他のゴルーチンはブロックされません。

私たちはある時点でCPUに束縛されたゴルーチンに対して同じことをするでしょう、しかし今のところ、あなたがユーザレベルの並列処理を望むならあなたは$ GOMAXPROCSを設定しなければなりません。 またはruntime.GOMAXPROCS(n)を呼び出します。 _ _

ゴルーチンは必ずしもOSスレッドに対応するわけではありません。 初期スタックサイズを小さくすることができ、スタックは必要に応じて大きくなります。

必要に応じて、複数のゴロイチンを単一のスレッドに多重化することができます。

さらに重要なことに、ゴルーチンはそれ自体をブロックしても他のゴルーチンをブロックしない順次プログラムであるという概念が上で概説した通りです。

Goroutinesはgccgoではpthreadとして実装されているので、OSスレッドと同じにすることもできます。 それはOSスレッドの概念とプログラミング時のマルチスレッドの考え方を切り離しています。


14


参照コンパイラ(5g / 6g / 8g)では、マスタースケジューラ( src/pkg/runtime/proc.c)はN個のOSスレッドを作成します。 Nはruntime.GOMAXPROCS(n)によって制御されます(デフォルトは1)。 各スケジューラスレッドは、マスターリストから新しいゴルーチンを取り出して実行を開始します。 ゴルーチンは、システムコールが行われるまで実行を続けます(例: printf)またはチャネル上の操作が行われ、その時点でスケジューラは次のgoroutineを取得し、中断した時点からそれを実行します(http://golang.org/src/pkgのgosched()呼び出しを参照)。 /runtime/chan.c[src/pkg/runtime/chan.c])。

すべての意図と目的のために、スケジューリングは coroutinesで実装されています。 setjmp()やlongjmp()を使って同じ機能をC言語で書くこともできますし、Go(および軽量/グリーンスレッドを実装している他の言語)もプロセスを自動化するだけです。

軽量スレッドの利点は、すべてのユーザースペースであるため、「スレッド」の作成は非常に安価で(小さなデフォルトスタックを割り当てる)、スレッド同士の対話方法に固有の構造があるため非常に効率的な場合があります。 欠点は、それらが本当のスレッドではないということです。つまり、すべてのスレッドが同時に実行されているように見える場合でも、単一の軽量スレッドがプログラム全体をブロックする可能性があります。


13


IMO、Goのマルチスレッドを魅力的なものにするのは通信機能です。通信インフラストラクチャ(mutex、キューなど)を構築しなければならないpthreadとは異なり、Goではデフォルトで便利な形式で利用できます。

手短に言えば、通信機能が優れているためにスレッドを使用することには「摩擦が少ない」ということができます(私が言えるのであればErlangに似ています)。


5


前の回答で述べたように、goルーチンは必ずしもシステムスレッドに対応しているわけではありませんが、現在マルチスレッドのパフォーマンスを向上させる必要がある場合は、次のものが便利です。

_ * Goランタイムの現在の実装は、デフォルトではこのコードを並列化しません*。 ユーザーレベルの処理に専念するのは単一のコアだけです。 システムコールでは任意の数のゴルーチンをブロックすることができますが、デフォルトでは、いつでも1つのみがユーザーレベルのコードを実行できます。 それはもっと賢くなければならず*いつかはもっと賢くなるでしょう*が、それが*なるまで*あなたがCPU並列処理を望むなら、あなたは同時にあなたが何コードを実行したいgoroutineを教える必要があります。 これを行うには2つの方法があります。 環境変数GOMAXPROCSを使用するコア数に設定してジョブを実行するか、ランタイムパッケージをインポートしてruntime.GOMAXPROCS(NCPU)を呼び出します。 有用な値はruntime.NumCPU()であり、これはローカルマシン上の論理CPUの数を報告します。 繰り返しになりますが、この要件はスケジューリングと実行時間が改善されたために廃止される予定です。 _

私のi5プロセッサを最大にするプログラム例はこれです(htopで100%で4つのコアすべてを使います):

package main


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


func main() {
    runtime.GOMAXPROCS(4) // Set the maximum number of threads/processes

    d := make(chan string)
    go boring("boring!", d, 1)
    go boring("boring!", d, 2)
    go boring("boring!", d, 3)
    go boring("boring!", d, 4)

    for i := 0; i < 10; i++ {
        time.Sleep(time.Second);
    }

    fmt.Println("You're boring; I'm leaving.")
}

func boring(msg string, c chan string, id int) {
    for i := 0; ; i++ {

    }
}

これは実際には何もしませんが、Javaなどの他の言語でマルチスレッドアプリケーションを作成するのに比べて、どれくらい短い/簡単/簡単かを確認します。