亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Go語言如何獲取goroutine的id

 更新時間:2024年12月09日 08:31:30   作者:江湖十年  
在Go語言中,獲取?goroutine的id并不像其他編程語言那樣容易,但依然有辦法,這篇文章就來和大家聊聊具體實現(xiàn)的方法,感興趣的小伙伴可以了解下

如果你使用過如 Python、Java 等主流支持并發(fā)的編程語言,那么通常都能夠比較容易的獲得進程和線程的 id。但是在 Go 語言,沒有直接提供對多進程和多線程的支持,而是提供了 goroutine 來支持并發(fā)編程。不過在 Go 中,獲取 goroutine 的 id 并不像其他編程語言那樣容易,但依然有辦法,本文就來介紹下如何實現(xiàn)。

獲取當前進程的 id

首先,雖然 Go 沒有提供多進程編程,但啟動 Go 程序還是會有一個進程存在的,Go 標準庫提供了 os.Getpid 函數(shù),可以方便的獲取當前進程的 id:

github.com/jianghushinian/blog-go-example/blob/main/goroutine/id/pid/main.go

package main

import (
	"fmt"
	"os"
)

func main() {
	// 獲取當前進程的 id
	pid := os.Getpid()
	fmt.Println("process id:", pid)
}

調用 os.Getpid() 會返回當前進程的 pid(進程 id)。

獲取當前 goroutine 的 id

Go 并沒有直接提供獲取 goroutine id 的方法,因為 goroutine 的管理是由 Go 運行時(Go runtime)負責的,它并不暴露每個 goroutine 的 id。然而,有一些方法可以間接獲取到與 goroutine 相關的信息。

使用 runtime 包獲取 goroutine id

雖然不能直接獲取每個 goroutine 的 id,但我們可以變相的通過 runtime.Stack 函數(shù)來獲取。

實現(xiàn)代碼如下:

github.com/jianghushinian/blog-go-example/blob/main/goroutine/id/main.go

package main

import (
	"fmt"
	"runtime"
	"strconv"
	"strings"
	"sync"
)

func GoId() int {
	buf := make([]byte, 32)
	n := runtime.Stack(buf, false)
	idField := strings.Fields(strings.TrimPrefix(string(buf[:n]), "goroutine "))[0]
	id, err := strconv.Atoi(idField)
	if err != nil {
		panic(fmt.Sprintf("cannot get goroutine id: %v", err))
	}
	return id
}

func main() {
	fmt.Println("main", GoId())
	var wg sync.WaitGroup
	for i := 0; i < 10; i++ {
		i := i
		wg.Add(1)
		go func() {
			defer wg.Done()
			fmt.Println(i, GoId())
		}()
	}
	wg.Wait()
}

這段代碼通過自定義的 GoId 函數(shù)來獲取當前 goroutine 的 id,并在 main 函數(shù)的主 goroutine 和子 goroutines 中打印它們的 id。

我們來解釋下 GoId 函數(shù)主要邏輯的實現(xiàn):

1.runtime.Stack(buf, false):

  • runtime.Stackruntime 包提供的公開函數(shù),用于獲取當前 goroutine 的堆棧信息。
  • 參數(shù) buf 是一個字節(jié)數(shù)組,用來存儲調用 runtime.Stack() 返回的堆棧信息。
  • 第二個參數(shù)是 false,表示我們只獲取當前 goroutine 的棧信息,如果為 true 則是獲取所有 goroutines 的棧信息。
  • runtime.Stack() 會將當前 goroutine 的棧信息寫入 buf 中,n 是返回的字節(jié)數(shù),表示堆棧信息的長度。

2.strings.TrimPrefix(string(buf[:n]), "goroutine "):

goroutine 1 [running]:
  • 將堆棧信息轉為字符串并去掉前綴 "goroutine "
  • 堆棧信息的第一行格式通常如下:
  • 這里通過 TrimPrefix 去除前綴 "goroutine " 后,剩下的內容就是 goroutine 的 id 及其狀態(tài)信息。

3.idField := strings.Fields(...)[0]:

  • strings.Fields 將經(jīng)過 TrimPrefix 處理后的字符串按空格切割成一個字符串切片。
  • 從切片中獲取第一個字段,這就是 goroutine 的 id,如 1

如果一切順利,GoId 函數(shù)最終返回當前 goroutine 的 id。

main 函數(shù)實現(xiàn)則比較簡單,先調用 GoId() 打印主 goroutine 的 id,然后啟動了 10 個子 goroutine 并分別打印它們的 id。

執(zhí)行示例代碼,得到如下輸出:

$ go run main.go
main 1
9 29
0 20
5 25
6 26
7 27
8 28
2 22
1 21
4 24
3 23

這樣,我們就變相的通過先獲取堆棧信息,然后再從堆棧信息中進行解析的方式拿到了 goroutine 的 id。想必你也能夠發(fā)現(xiàn),這種實現(xiàn)方式性能不高,所以不到萬不得已,不要輕易獲取 goroutine 的 id。

那么有沒有更高效的方式呢?

很遺憾,Go 官方?jīng)]有提供。不過有第三方庫幫我們實現(xiàn)了。

使用第三方庫獲取 goroutine id

一個比較常用的庫是 github.com/petermattis/goid,可以用來獲取當前 goroutine 的 id。

安裝方式:

$ go get github.com/petermattis/goid

使用示例:

github.com/jianghushinian/blog-go-example/blob/main/goroutine/id/goid/main.go

package main

import (
	"fmt"
	"sync"

	"github.com/petermattis/goid"
)

func main() {
	fmt.Println("main", goid.Get())
	var wg sync.WaitGroup
	for i := 0; i < 10; i++ {
		i := i
		wg.Add(1)
		go func() {
			defer wg.Done()
			fmt.Println(i, goid.Get())
		}()
	}
	wg.Wait()
}

執(zhí)行示例代碼,得到如下輸出:

$ go run goid/main.go
main 1
9 43
4 38
5 39
6 40
7 41
8 42
1 35
0 34
2 36
3 37

我們僅需要調用 goid.Get() 即可獲取當前 goroutine 的 id。

goid 庫使用了 C 和 匯編來獲取 goroutine id,所以性能更好。并且 goid 為所有的 Go 版本都做了兼容,從項目文件名可以看出,不同 Go 版本有著不同的實現(xiàn):

$ tree goid
goid
├── LICENSE
├── README.md
├── go.mod
├── goid.go
├── goid_gccgo.go
├── goid_go1.3.c
├── goid_go1.3.go
├── goid_go1.4.go
├── goid_go1.4.s
├── goid_go1.5.go
├── goid_go1.5.s
├── goid_slow.go
├── goid_test.go
├── runtime_gccgo_go1.8.go
├── runtime_go1.23.go
├── runtime_go1.5.go
├── runtime_go1.6.go
└── runtime_go1.9.go

1 directory, 18 files

goid_go1.3.c 中可以看到 C 語言版本實現(xiàn)如下:

github.com/petermattis/goid/blob/master/goid_go1.3.c

// +build !go1.4

#include <runtime.h>

void ·Get(int64 ret) {
    ret = g->goid;
    USED(&ret);
}

goid_go1.4.s 中可以看到匯編語言版本實現(xiàn)如下:

github.com/petermattis/goid/blob/master/goid_go1.4.s

// +build amd64 amd64p32 arm 386
// +build go1.4,!go1.5

#include "textflag.h"

#ifdef GOARCH_arm
#define JMP B
#endif

TEXT ·getg(SB),NOSPLIT,$0-0
	JMP	runtime·getg(SB)

此外,為了保證兼容性,在 goid.go 中還有一個 Go 語言版本實現(xiàn):

github.com/petermattis/goid/blob/master/goid.go

package goid

import (
	"bytes"
	"runtime"
	"strconv"
)

func ExtractGID(s []byte) int64 {
	s = s[len("goroutine "):]
	s = s[:bytes.IndexByte(s, ' ')]
	gid, _ := strconv.ParseInt(string(s), 10, 64)
	return gid
}

// Parse the goid from runtime.Stack() output. Slow, but it works.
func getSlow() int64 {
	var buf [64]byte
	return ExtractGID(buf[:runtime.Stack(buf[:], false)])
}

這里 Go 版本的實現(xiàn)同樣使用 runtime.Stack(),并且注釋也標明了這個實現(xiàn)比較慢。

所以,如果我們真的需要獲取 goroutine 的 id,那么推薦使用 goid。

總結

在 Go 中獲取當前進程的 id 可以使用 os.Getpid() 函數(shù)。如果要獲取當前 goroutine 的 id 則要困難一些,Go 標準庫沒有直接提供該功能,不過我們可以變相的從 runtime.Stack() 返回的堆棧信息中獲取,也可以使用第三方庫 goid 來獲取。

以上就是Go語言如何獲取goroutine的id的詳細內容,更多關于Go獲取goroutine的id的資料請關注腳本之家其它相關文章!

相關文章

  • 使用golang在windows上設置全局快捷鍵的操作

    使用golang在windows上設置全局快捷鍵的操作

    最近在工作中,總是重復的做事,想著自己設置一個快捷鍵實現(xiàn)windows 剪貼板的功能,所以本文小編給大家分享了使用golang在windows上設置全局快捷鍵的操作,文中有相關的代碼示例供大家參考,需要的朋友可以參考下
    2024-02-02
  • Go?gRPC進階教程服務超時設置

    Go?gRPC進階教程服務超時設置

    這篇文章主要為大家介紹了Go?gRPC進階,gRPC請求的超時時間設置,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-06-06
  • 源碼解析gtoken替換jwt實現(xiàn)sso登錄

    源碼解析gtoken替換jwt實現(xiàn)sso登錄

    這篇文章主要為大家介紹了源碼解析gtoken替換jwt實現(xiàn)sso登錄的示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-06-06
  • 深入解析Go語言中crypto/subtle加密庫

    深入解析Go語言中crypto/subtle加密庫

    本文主要介紹了深入解析Go語言中crypto/subtle加密庫,詳細介紹crypto/subtle加密庫主要函數(shù)的用途、工作原理及實際應用,具有一定的參考價值,感興趣的可以了解一下
    2024-02-02
  • win10下go mod配置方式

    win10下go mod配置方式

    這篇文章主要介紹了win10下go mod配置方式,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2021-04-04
  • Go切片擴容機制詳細說明和舉例

    Go切片擴容機制詳細說明和舉例

    Go 語言中的切片是一種動態(tài)數(shù)組,它可以自動擴容和縮容以適應不同的數(shù)據(jù)量,這篇文章主要給大家介紹了關于Go切片擴容機制詳細說明和舉例的相關資料,文中通過代碼介紹的非常詳細,需要的朋友可以參考下
    2024-03-03
  • golang 占位符和fmt常見輸出介紹

    golang 占位符和fmt常見輸出介紹

    這篇文章主要介紹了golang 占位符和fmt常見輸出介紹,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-12-12
  • Go語言編程中判斷文件是否存在是創(chuàng)建目錄的方法

    Go語言編程中判斷文件是否存在是創(chuàng)建目錄的方法

    這篇文章主要介紹了Go語言編程中判斷文件是否存在是創(chuàng)建目錄的方法,示例都是使用os包下的函數(shù),需要的朋友可以參考下
    2015-10-10
  • Go語言實現(xiàn)字符串切片賦值的方法小結

    Go語言實現(xiàn)字符串切片賦值的方法小結

    這篇文章主要給大家介紹了Go語言實現(xiàn)字符串切片賦值的兩種方法,分別是在for循環(huán)的range中以及在函數(shù)的參數(shù)傳遞中實現(xiàn),有需要的朋友們可以根據(jù)自己的需要選擇使用。下面來一起看看吧。
    2016-10-10
  • 如何在golang中檢查文件是否存在

    如何在golang中檢查文件是否存在

    如果你用的是?Python,可通過?os.path.exists?這樣的標準庫函數(shù)實現(xiàn),遺憾的是,Go?標準庫沒有提供這樣直接的函數(shù),所以下面我們就來了解下如何使用GO語言能實現(xiàn)檢查文件是否存在呢
    2024-02-02

最新評論