⬆️ ⬇️

SetGoroutineName

In Go, more than a million goroutine can be launched, and this mechanism is fascinating until there is a problem. For example, a memory leak or dead-lock.



The first thing I want to do is figure it out, look at what is happening.

image



It can be done like this.



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



Or so:



 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



We see that in these examples one gorutin is running and its stack is traced, but if we have 20-30 identical goroutines, then the question is, who do they serve? If this is a site, then maybe the user who left, and goroutine has not ceased to exist, and as a result does not release the memory?



There is a desire to give the names of the gorutinos and to write in the title a useful, useful information, such as the Id of the user whom she services. But Go is not easy, because there is no SetGoroutineName or GetGoroutineId . Such functions are evil in the opinion of the creators of the Go language. It's hard not to agree with people like Rob and Ken. But evil is not because these functions are evil at all, but because programmers will start using these functions incorrectly. Not for debugging applications at the time of memory leaks, but simply as goroutine local storage. That is, in the logic of the program it is bad to use such things, but if you have got it wrong, you still need to somehow find the error.



PyraDebug



So you need to give the names of the gorutins, but whatever the application logic does not depend on it. So was born 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 


An important feature of the library is pyraDebug.Enable = true , that is, after debugging, you simply pyraDebug.Enable = true it off and it stops doing something and therefore cannot rely on SetGoroutineName in logic.



Initially, I wanted to indicate the name of the gurutin, which gave birth to it, but in practice I need only the name, the source code of the 127 line. It is easy to fork, understand and modify.



The library depends on the text format that gives runtime.Stack and may stop working in the future, which is also good that developers do not rely thoughtlessly on this library and use it only for debugging.



Ps. It is always interesting to know what bike did.



https://github.com/CossackPyra/pyradebug



')

Source: https://habr.com/ru/post/318220/



All Articles