В Go может быть запущенно больше миллиона goroutine, и этот механизм вызывает восторг до того момента, пока не появляется какая-либо проблема. Например, утечка памяти или dead-lock.
Первое, что хочется сделать это разобраться, посмотреть на то, что же происходит.

это можно сделать так
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
Мы видим, что в данных примерах запущенна одна гоурутина и ее стек трейс, но если у нас 20-30 одинаковых goroutine, то возникает вопрос кого они обслуживают? Если это сайт, то может быть пользователь, который ушел, а goroutine не прекратила своё существование, и как следствие не освобождает память?
Появляется желание давать гоурутинам названия и в название вписать свякую полезную инфу, как например Id пользователя, которого она обслуживаниет. Но в Go непросто так нет функции SetGoroutineName или GetGoroutineId. Такие функции — зло по мнению создателей языка Go. Трудно не согласиться с такими людми как Rob и Ken. Но зло это не потому, что вообще эти функции зло, а потому, что эти функции программисты начнут использовать неправильно. Не для отладки приложений в момент утечки памяти, а просто как goroutine local storage. То есть, в логике программы плохо использовать такие штуки, но если накосячили, то все же ошибку надо как-то найти.
PyraDebug
Значит нужно давать имена горутинам, но что-бы логика приложения от этого не зависела. Так и родилась 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 в логике нельзя.
Изначально я хотел указывать еще имя гоурутины, что породила её, но на практике мне достаточно только имя, исходный код 127 строки. Его легко форкнуть, разобраться и доработать.
Библитека зависит от текстового формата, который выдает runtime.Stack и может перестать работать в будущем, что так-же хорошо, чтобы разработчики не полагались бездумно на это библитеку и использовали ее только для отладки.
PS. Всегда интересно узнать, что сделал велосепед
https://github.com/CossackPyra/pyradebug
ссылка на оригинал статьи https://habrahabr.ru/post/318220/
Добавить комментарий