最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Go語(yǔ)言如何獲取goroutine的id

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

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

獲取當(dāng)前進(jìn)程的 id

首先,雖然 Go 沒有提供多進(jìn)程編程,但啟動(dòng) Go 程序還是會(huì)有一個(gè)進(jìn)程存在的,Go 標(biāo)準(zhǔn)庫(kù)提供了 os.Getpid 函數(shù),可以方便的獲取當(dāng)前進(jìn)程的 id:

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

package main

import (
	"fmt"
	"os"
)

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

調(diào)用 os.Getpid() 會(huì)返回當(dāng)前進(jìn)程的 pid(進(jìn)程 id)。

獲取當(dāng)前 goroutine 的 id

Go 并沒有直接提供獲取 goroutine id 的方法,因?yàn)?goroutine 的管理是由 Go 運(yùn)行時(shí)(Go runtime)負(fù)責(zé)的,它并不暴露每個(gè) goroutine 的 id。然而,有一些方法可以間接獲取到與 goroutine 相關(guān)的信息。

使用 runtime 包獲取 goroutine id

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

實(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()
}

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

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

1.runtime.Stack(buf, false):

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

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

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

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

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

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

main 函數(shù)實(shí)現(xiàn)則比較簡(jiǎn)單,先調(diào)用 GoId() 打印主 goroutine 的 id,然后啟動(dòng)了 10 個(gè)子 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

這樣,我們就變相的通過(guò)先獲取堆棧信息,然后再?gòu)亩褩P畔⒅羞M(jìn)行解析的方式拿到了 goroutine 的 id。想必你也能夠發(fā)現(xiàn),這種實(shí)現(xiàn)方式性能不高,所以不到萬(wàn)不得已,不要輕易獲取 goroutine 的 id。

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

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

使用第三方庫(kù)獲取 goroutine id

一個(gè)比較常用的庫(kù)是 github.com/petermattis/goid,可以用來(lái)獲取當(dāng)前 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

我們僅需要調(diào)用 goid.Get() 即可獲取當(dāng)前 goroutine 的 id。

goid 庫(kù)使用了 C 和 匯編來(lái)獲取 goroutine id,所以性能更好。并且 goid 為所有的 Go 版本都做了兼容,從項(xiàng)目文件名可以看出,不同 Go 版本有著不同的實(shí)現(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 語(yǔ)言版本實(shí)現(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 中可以看到匯編語(yǔ)言版本實(shí)現(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 中還有一個(gè) Go 語(yǔ)言版本實(shí)現(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 版本的實(shí)現(xiàn)同樣使用 runtime.Stack(),并且注釋也標(biāo)明了這個(gè)實(shí)現(xiàn)比較慢。

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

總結(jié)

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

以上就是Go語(yǔ)言如何獲取goroutine的id的詳細(xì)內(nèi)容,更多關(guān)于Go獲取goroutine的id的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • 淺析go語(yǔ)言如何實(shí)現(xiàn)協(xié)程的搶占式調(diào)度的

    淺析go語(yǔ)言如何實(shí)現(xiàn)協(xié)程的搶占式調(diào)度的

    go語(yǔ)言通過(guò)GMP模型實(shí)現(xiàn)協(xié)程并發(fā),為了避免單協(xié)程持續(xù)持有線程導(dǎo)致線程隊(duì)列中的其他協(xié)程饑餓問(wèn)題,設(shè)計(jì)者提出了一個(gè)搶占式調(diào)度機(jī)制,本文會(huì)基于一個(gè)簡(jiǎn)單的代碼示例對(duì)搶占式調(diào)度過(guò)程進(jìn)行深入講解剖析
    2024-04-04
  • golang copy函數(shù)使用的坑

    golang copy函數(shù)使用的坑

    本文主要介紹了golang copy函數(shù)使用的坑,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2023-04-04
  • go語(yǔ)言之給定英語(yǔ)文章統(tǒng)計(jì)單詞數(shù)量(go語(yǔ)言小練習(xí))

    go語(yǔ)言之給定英語(yǔ)文章統(tǒng)計(jì)單詞數(shù)量(go語(yǔ)言小練習(xí))

    這篇文章給大家分享go語(yǔ)言小練習(xí)給定英語(yǔ)文章統(tǒng)計(jì)單詞數(shù)量,實(shí)現(xiàn)思路大概是利用go語(yǔ)言的map類型,以每個(gè)單詞作為關(guān)鍵字存儲(chǔ)數(shù)量信息,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),需要的朋友參考下吧
    2020-01-01
  • golang中new與make的區(qū)別講解

    golang中new與make的區(qū)別講解

    new只能開辟單個(gè)空間,不能為引用類型開辟多個(gè)空間,并且new是對(duì)類型進(jìn)行內(nèi)存的開辟,返回一個(gè)指向該內(nèi)存空間的指針類型,如果使用new去初始化引用數(shù)據(jù)類型,不是很合適(當(dāng)然,new一個(gè)對(duì)象還是可以的),因此就需要用到另一個(gè)內(nèi)置函數(shù)make,需要的朋友可以參考下
    2023-01-01
  • Go Slice擴(kuò)容的這些坑你踩過(guò)哪些

    Go Slice擴(kuò)容的這些坑你踩過(guò)哪些

    這篇文章主要為大家詳細(xì)介紹了Golang中對(duì)切片Slice的append操作時(shí)會(huì)遇到的踩坑經(jīng)驗(yàn)分享,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以了解一下
    2023-03-03
  • Golang測(cè)試框架goconvey進(jìn)行單元測(cè)試流程介紹

    Golang測(cè)試框架goconvey進(jìn)行單元測(cè)試流程介紹

    goconvey是一款針對(duì)Golang的測(cè)試框架,可以管理和運(yùn)行測(cè)試用例,同時(shí)提供了豐富的斷言函數(shù),并支持很多Web界面特性,這篇文章主要介紹了使用goconvey進(jìn)行單元測(cè)試流程,感興趣的同學(xué)可以參考下文
    2023-05-05
  • Golang sync包中errgroup的使用詳解

    Golang sync包中errgroup的使用詳解

    Go 語(yǔ)言為我們提供了豐富的并發(fā)原語(yǔ),且大多數(shù)都位于 sync 包下,今天我們來(lái)探討一下該庫(kù)下的原語(yǔ)之一:errgroup,感興趣的小伙伴可以了解一下
    2023-05-05
  • go實(shí)現(xiàn)base64編碼的四種方式

    go實(shí)現(xiàn)base64編碼的四種方式

    本文主要介紹了go實(shí)現(xiàn)base64編碼的四種方式,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2023-03-03
  • 基于context.Context的Golang?loader緩存請(qǐng)求放大問(wèn)題解決

    基于context.Context的Golang?loader緩存請(qǐng)求放大問(wèn)題解決

    這篇文章主要為大家介紹了基于context.Context的Golang?loader緩存請(qǐng)求放大解決方案,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-05-05
  • go語(yǔ)言gin框架中間件詳解

    go語(yǔ)言gin框架中間件詳解

    在Go語(yǔ)言中,gin是一個(gè)常用的Web框架,用于構(gòu)建RESTful API和Web應(yīng)用程序。本文將通過(guò)代碼示例詳細(xì)介紹了gin框架中間件,感興趣的同學(xué)可以參考閱讀
    2023-04-04

最新評(píng)論

鸡西市| 赤水市| 双桥区| 岳阳市| 马尔康县| 永寿县| 清新县| 德化县| 兰溪市| 山阳县| 资中县| 镇沅| 吉木乃县| 佳木斯市| 英德市| 鄂温| 莎车县| 沙坪坝区| 清水河县| 乐至县| 炉霍县| 启东市| 敦煌市| 秭归县| 花莲县| 上饶市| 龙陵县| 嘉义市| 五大连池市| 安国市| 万宁市| 彰化市| 华坪县| 延津县| 庄浪县| 洱源县| 策勒县| 行唐县| 麟游县| 东至县| 榆社县|