If you have used mainstream programming languages that support concurrency such as Python and Java, you can usually get the ids of processes and threads more easily. However, in Go, there is no direct support for multi-process and multi-threading, but goroutine is provided to support concurrent programming. However, in Go, getting the id of goroutine is not as easy as other programming languages, but there is still a way. This article will introduce how to implement it.
Get the id of the current process
First of all, although Go does not provide multi-process programming, there will still be a process when starting Go programs. The Go standard library providesFunctions can easily obtain the id of the current process:
/jianghushinian/blog-go-example/blob/main/goroutine/id/pid/
package main import ( "fmt" "os" ) func main() { // Get the id of the current process pid := () ("process id:", pid) }
Call()
The pid (process id) of the current process will be returned.
Get the id of the current goroutine
Go does not directly provide a way to get the goroutine id, because the management of goroutine is handled by the Go runtime, and it does not expose the id of each goroutine. However, there are some ways to get indirect information related to goroutine.
Use the runtime package to get the goroutine id
Although we cannot directly obtain the id of each goroutine, we can pass it in disguisefunction to obtain.
The implementation code is as follows:
/jianghushinian/blog-go-example/blob/main/goroutine/id/
package main import ( "fmt" "runtime" "strconv" "strings" "sync" ) func GoId() int { buf := make([]byte, 32) n := (buf, false) idField := ((string(buf[:n]), "goroutine "))[0] id, err := (idField) if err != nil { panic(("cannot get goroutine id: %v", err)) } return id } func main() { ("main", GoId()) var wg for i := 0; i < 10; i++ { i := i (1) go func() { defer () (i, GoId()) }() } () }
This code is customizedGoId
function to get the id of the current goroutine andmain
Print their ids in the main goroutine and child goroutines of the function.
Let's explainGoId
Implementation of main logic of function:
1.(buf, false):
-
yes
runtime
A public function provided by the package to obtain the stack information of the current goroutine. - parameter
buf
is a byte array used to store calls()
Returned stack information. - The second parameter is
false
, means that we only get the stack information of the current goroutine, iftrue
This is to get the stack information of all goroutines. -
()
The stack information of the current goroutine will be written tobuf
middle,n
is the number of bytes returned, indicating the length of the stack information.
2.(string(buf[:n]), "goroutine "):
goroutine 1 [running]:
- Convert stack information to string and remove prefixes
"goroutine "
。 - The first line format of the stack information is usually as follows:
- Passed here
TrimPrefix
Remove prefixes"goroutine "
After that, the rest is the id of the goroutine and its status information.
3.idField := (...)[0]:
-
Will pass
TrimPrefix
The processed string is cut into a string slice by space. - Get the first field from the slice, this is the id of the goroutine, like
1
。
If everything goes well,GoId
The function finally returns the id of the current goroutine.
main
Function implementation is relatively simple, call it firstGoId()
Print the id of the main goroutine, then start the 10 sub goroutines and print their ids separately.
Execute the sample code and get the following output:
$ go run
main 1
9 29
0 20
5 25
6 26
7 27
8 28
2 22
1 21
4 24
3 23
In this way, we get the goroutine id by first obtaining the stack information and then parsing it from the stack information. I believe you can also find that this implementation method is not performing well, so don’t easily get the goroutine id unless it is absolutely necessary.
So is there a more efficient way?
Unfortunately, Go does not provide it. However, there is a third-party library that helps us realize it.
Use third-party libraries to get goroutine id
A more commonly used library is/petermattis/goid, can be used to get the id of the current goroutine.
Installation method:
$ go get /petermattis/goid
Example of usage:
/jianghushinian/blog-go-example/blob/main/goroutine/id/goid/
package main import ( "fmt" "sync" "/petermattis/goid" ) func main() { ("main", ()) var wg for i := 0; i < 10; i++ { i := i (1) go func() { defer () (i, ()) }() } () }
Execute the sample code and get the following output:
$ go run goid/
main 1
9 43
4 38
5 39
6 40
7 41
8 42
1 35
0 34
2 36
3 37
We only need to call()
You can get the id of the current goroutine.
goid
The library uses C and assembly to get the goroutine id, so the performance is better. andgoid
All Go versions are compatible. As can be seen from the project file name, different Go versions have different implementations:
$ tree goid goid ├── LICENSE ├── ├── ├── ├── goid_gccgo.go ├── goid_go1. ├── goid_go1. ├── goid_go1. ├── goid_go1. ├── goid_go1. ├── goid_go1. ├── goid_slow.go ├── goid_test.go ├── runtime_gccgo_go1. ├── runtime_go1. ├── runtime_go1. ├── runtime_go1. └── runtime_go1. 1 directory, 18 files
existgoid_go1.
You can see that the implementation of the C language version is as follows:
/petermattis/goid/blob/master/goid_go1.
// +build !go1.4 #include <> void ·Get(int64 ret) { ret = g->goid; USED(&ret); }
existgoid_go1.
You can see that the assembly language version is implemented as follows:
/petermattis/goid/blob/master/goid_go1.
// +build amd64 amd64p32 arm 386 // +build go1.4,!go1.5 #include "" #ifdef GOARCH_arm #define JMP B #endif TEXT ·getg(SB),NOSPLIT,$0-0 JMP runtime·getg(SB)
In addition, in order to ensure compatibility,There is also a Go language version implementation:
/petermattis/goid/blob/master/
package goid import ( "bytes" "runtime" "strconv" ) func ExtractGID(s []byte) int64 { s = s[len("goroutine "):] s = s[:(s, ' ')] gid, _ := (string(s), 10, 64) return gid } // Parse the goid from () output. Slow, but it works. func getSlow() int64 { var buf [64]byte return ExtractGID(buf[:(buf[:], false)]) }
Here the implementation of Go version is also used()
, and the comments also indicate that this implementation is slower.
So, if we really need to get the id of goroutine, it is recommended to use itgoid。
Summarize
Get the id of the current process in Go and you can use it()
function. It is more difficult to obtain the current goroutine id. The Go standard library does not directly provide this function, but we can use it in disguise.()
The returned stack information can also be obtained from the third-party library.goidCome to get it.
The above is the detailed content of how to obtain goroutine id in Go. For more information about Go obtaining goroutine id, please follow my other related articles!