SetGoroutineName

Goでは100万を超えるゴルーチンを起動できますが、このメカニズムは問題が発生するまで喜んでいます。 たとえば、メモリリークまたはデッドロック。







私が最初にやりたいことはそれを把握することです。何が起こっているのかを見てください。

画像







このようにすることができます。







package main import ( "bytes" "fmt" "runtime/pprof" ) func main() { profiler := pprof.Lookup("goroutine") var buf bytes.Buffer profiler.WriteTo(&buf, 1) fmt.Println(buf.String()) }
      
      





 goroutine profile: total 1 1 @ 0xb1620 0xb1340 0xac9c0 0x200c0 0x59f80 0x98d61 # 0xb161f runtime/pprof.writeRuntimeProfile+0xdf /usr/local/go/src/runtime/pprof/pprof.go:614 # 0xb133f runtime/pprof.writeGoroutine+0x9f /usr/local/go/src/runtime/pprof/pprof.go:576 # 0xac9bf runtime/pprof.(*Profile).WriteTo+0xff /usr/local/go/src/runtime/pprof/pprof.go:298 # 0x200bf main.main+0xbf /tmp/sandbox627252447/main.go:12 # 0x59f7f runtime.main+0x39f /usr/local/go/src/runtime/proc.go:183
      
      





https://play.golang.org/p/ysl_avotLS







または:







 package main import ( "fmt" "runtime" ) func main() { b1 := make([]byte, 1<<20) runtime.Stack(b1, true) s1 := string(b1) fmt.Println(s1) }
      
      





 goroutine 1 [running]: main.main() /tmp/sandbox952340390/main.go:10 +0x80
      
      





https://play.golang.org/p/FCbzn2_DlQ







これらの例ではゴルチンとそのスタックトレースが1つ起動されていますが、20〜30個の同一のゴルーチンがある場合、疑問が生じます。 これがサイトの場合、退去したユーザーがいる可能性がありますが、ゴルーチンは存在しなくなり、その結果、メモリが解放されませんか?







gourutinsに名前を付けて、役立つユーザーのIDなどの便利な情報を名前に入力したいという要望があります。 しかし、Goは簡単ではないため、 SetGoroutineName



またはGetGoroutineId



はありません。 Go言語の作成者によると、このような機能は悪です。 ロブやケンのような人々に反対するのは難しい。 しかし、悪は、これらの機能が一般的に悪であるためではなく、プログラマがこれらの機能を誤って使用し始めるためです。 メモリリーク時にアプリケーションをデバッグするためではなく、ゴルーチンのローカルストレージのように。 つまり、プログラムのロジックでは、そのようなものを使用するのは悪いことですが、それらが台無しになった場合は、何らかの形でエラーを見つける必要があります。







ピラデバグ



したがって、ゴルーチンに名前を付ける必要がありますが、アプリケーションロジックがゴルーチンに依存しないものは何でも。 pyradebug



が生まれた







 go get -u github.com/CossackPyra/pyradebug
      
      





 package main import ( "fmt" "log" "net/http" "time" "github.com/CossackPyra/pyradebug" ) var pyraDebug *pyradebug.PyraDebug func main() { pyraDebug = pyradebug.InitPyraDebug() pyraDebug.Enable = true for i := 0; i < 10; i++ { go func(i int) { pyraDebug.SetGoroutineName(fmt.Sprintf("sleep func %d", i)) for { time.Sleep(time.Second) } }(i) } http.HandleFunc("/goroutine", handle_goroutine) log.Fatal(http.ListenAndServe(":8765", nil)) } func handle_goroutine(w http.ResponseWriter, r *http.Request) { agi := pyraDebug.ListGoroutines(1<<20, true) w.Header().Set("Content-Type", "text/plain") for i, gi := range agi { fmt.Fprintf(w, "%d\t%s\t%s\t%s\n", i, gi.Id, gi.Name, gi.Status) } }
      
      





 # http://127.0.0.1:8765/goroutine 0 goroutine 31 running 1 goroutine 1 IO wait 2 goroutine 17 syscall, locked to thread 3 goroutine 20 sleep func 0 sleep 4 goroutine 21 sleep func 1 sleep 5 goroutine 22 sleep func 2 sleep 6 goroutine 23 sleep func 3 sleep 7 goroutine 24 sleep func 4 sleep 8 goroutine 25 sleep func 5 sleep 9 goroutine 26 sleep func 6 sleep 10 goroutine 27 sleep func 7 sleep 11 goroutine 28 sleep func 8 sleep 12 goroutine 29 sleep func 9 sleep
      
      





ライブラリの重要な機能はpyraDebug.Enable = true



。つまり、デバッグ後、単にオフにし、何もしなくなります。 SetGoroutineName



、ロジックでSetGoroutineName



に依存することはできません。







最初は、ゴルチンの名前も表示したかったのですが、それが生まれたので、実際には127行のソースコードという名前だけが必要です。 フォーク、理解、および変更は簡単です。







このライブラリは、 runtime.Stack



が提供runtime.Stack



テキスト形式に依存しており、将来動作runtime.Stack



なくなる可能性があります。これは、開発者がこのライブラリにruntime.Stack



依存せず、デバッグにのみ使用する場合にも適しています。







PS。 自転車が何をしたかを知ることは常に興味深いです







https://github.com/CossackPyra/pyradebug








All Articles