2017-10-08 9 views
2

ゴーのドキュメントは言うこと:ゴルーチンがブロックされているかどうかをランタイムチェックで調べる方法はありますか?

、彼らが勝ったので、このようなブロッキングシステムコールを呼び出すのと同じコルーチンブロックは、実行時には自動的に別の、実行可能なスレッドに同じオペレーティング・システム・スレッド上の他のコルーチンを動かしますブロックされない

しかし、実行時にゴルーチンがブロックされていることをどのように検出するのですか?

たとえば、go-routineの1つで計算を実行すると、ブロック操作として評価されますか?

package main 

import (
    "fmt" 
    "runtime" 
) 

func f(from string, score int) { 
    for i := 0; i < score; i++ { 
      for z := 0; z < score; z++ { 
     } 
    } 

    fmt.Println(from, " Done") 
} 

func main() { 
runtime.GOMAXPROCS(1) 
f("direct", 300000) 
go f("foo", 200000) 
go f("bar", 20000) 
go f("baz", 2000) 

go func(msg string) { 
     fmt.Println(msg) 
    }("going without loop") 

     var input string 
    fmt.Scanln(&input) 
    fmt.Println("done") 
} 

私は結果を得ています:baz、boo bar。しかし、なぜ? fooはブロックしていますか?

+0

http://blog.alexnesterov.com/post/coroutines-part-1/もおもしろいです(Kotlinについては、Goを参照してください) – VonC

答えて

1

このチケットが質問に関連する:

https://github.com/golang/go/issues/11462

各ブロックは、ランタイムによって提供されます、あなたが行うことができます呼び出します。したがって、ランタイムは何かが発生してブロックする可能性があることを知っています。例えば

:あなたはsync.MutexLock()を呼び出す場合

  1. ランタイムは、そのブロックまたはないし、それに応じて行動するだろう天気をチェックを処理します。あなたはexec.CmdRun()またはOutput()(など)を呼び出した場合

  2. ランタイムは、この呼び出しはブロックすること、それに気づくと想定しています。あなたが走っているプログラムがブロックするかどうかは分からないので、最悪の場合を想定しなければなりません。

私の知っている限り、ゴルーチンがブロックする方法と、上記の例がそれぞれの例です。

  1. 「外部」ヘルプなしでランタイムが提供するものの例です。

  2. システムコールが関与していたものの例です。たとえばGolang on linuxはgnu libcを使用せず、osを呼び出すことによって直接必要なsyscallsを実装します。これらの呼び出しはすべてパッケージsyscall(私の知る限り)を経由しています。ここで実行時には何が起こるかを通知する単一のフックがあります。もちろん

ことがあるかもしれないように画像が少し濁っている、そのgolangも1.クロスOSスレッドの同期のためのOSからのミューテックスを必要とし、それは何らかの形でも実施例2

のビットであります

問題のコードについて:ループがコンパイラによって最適化されていないと、Goは時間がかかることを理解していません。そして、このようなタイトなループでは、goスケジューラはゴルーチンを「停止」することができず、別のループを実行中に設定することはできません。だから、たくさんのループがあるようなゴルーチンがたくさんある場合には、少なくとも1つのタイトなループが完了するまで、それらはあなたのCPUを食べて、他のすべてのゴルーチンが待たなければなりません。 しかし、ループ内の別の関数を呼び出すだけでその画像が変更され、関数呼び出しとして が優先されます。

user1432751はコメントで尋ねた:

動作遮断が発生したときのCPUレジスタと何が起こりますか? 現在のスレッドはゴルーチンによってブロックされています。スケジューラは新しい システムスレッドを作成し、そこに他のすべてのスレッドを移行しますか? -

行くスケジュールは、特定のプリエンプションポイントでプリエンプティブ(少なくとも、それは私がチェックした最後の時間状態だった)が、スケジュールではありません。例えば、syscalls、チャンネルでの送信と待機、そして関数呼び出しを正しく覚えているかどうか。したがって、これらのポイントでは、内部関数が呼び出され、スケジューラが何をすべきかを決めるときに、goroutineで実行されているコードに関連するCPUレジスタ関連のものが既にスタックにあります。

そして、システムコールが行われ、したがって、ブロックされたOSスレッドの危険性があるYesであれば、システムコールをしているゴルーチンもGOMAXPROCSにカウントされません独自のOSスレッドを取得します。

+0

ブロック操作が行われるとCPUのレジスタはどうなりますか?現在のスレッドはゴルーチンによってブロックされています。スケジューラは新しいシステムスレッドを作成し、他のすべてのスレッドをそこに移行しますか? –

+0

質問に対する私の答えはあなたのコメントに答えました。 – Krom

1

通常、このコンテキストでのブロックは、ゴルーチンが実行時に通常はシステムコール経由で作業を要求したときに発生します。例えば、ソケットを聴く - ゴルーチンは、データが到着したときにシステムを起動させるためにシステムのkqueue/epoll部分に指示します。この時点で、goroutineは非常に明らかにブロックされています。

チャンネルでメッセージを待っているときにも、ゴルーチンがブロックされます。ここで、ゴルーチンは、メッセージを受信するまで何もしないことを明示的にランタイムに伝えました。したがって、ランタイムは、ゴルーチンがブロックされます。

"これを実行して結果を出す"または "準備が整ったらこれを教えてください"という操作は、すべて検証可能な操作をブロックし、準備が整うまで眠りにつきます。

関連する問題