1 回答

TA貢獻(xiàn)1811條經(jīng)驗(yàn) 獲得超5個(gè)贊
每個(gè)函數(shù)都是從 goroutine 調(diào)用的,甚至是main()
函數(shù)(稱(chēng)為 goroutine?main
)。
Go 中的 goroutine 沒(méi)有身份。哪個(gè) goroutine 調(diào)用函數(shù)并不重要。
回答你的“原始”問(wèn)題:
有什么方法可以查明正在運(yùn)行的函數(shù)是否被調(diào)用為 goroutine 嗎?
如果我們將 this 定義為使用該go
語(yǔ)句或不使用該語(yǔ)句調(diào)用的函數(shù),那么答案是肯定的:我們可以檢查這一點(diǎn)。
但在此之前:我不會(huì)將此信息用于任何用途。不要編寫(xiě)依賴(lài)于此的代碼,也不要編寫(xiě)依賴(lài)于哪個(gè) goroutine 調(diào)用函數(shù)的代碼。如果需要從多個(gè) goroutine 同時(shí)訪問(wèn)資源,只需使用適當(dāng)?shù)耐郊纯伞?/p>
基本上我們可以檢查調(diào)用堆棧:相互調(diào)用的函數(shù)列表。如果該函數(shù)位于該列表的頂部,則使用它來(lái)調(diào)用它go
(檢查答案末尾的注釋?zhuān)?。如果調(diào)用堆棧中在該函數(shù)之前還有其他函數(shù),則從go
另一個(gè)函數(shù)(位于調(diào)用堆棧中之前的函數(shù))調(diào)用該函數(shù),而無(wú)需使用 , 。
我們可以用來(lái)runtime.Callers()
獲取調(diào)用 goroutine 的堆棧。這是我們檢查是否有其他函數(shù)調(diào)用“us”的方法:
func f(name string) {
? ? count := runtime.Callers(3, make([]uintptr, 1))
? ? if count == 0 {
? ? ? ? fmt.Printf("%q is launched as new\n", name)
? ? }
}
測(cè)試它:
func main() {
? ? f("normal")
? ? go f("with-go")
? ? func() { f("from-anon") }()
? ? func() { go f("from-anon-with-go") }()
? ? f2("from-f2")
? ? go f2("with-go-from-f2")
? ? f3("from-f3")
? ? go f3("with-go-from-f3")
? ? time.Sleep(time.Second)
}
func f2(name string) { f(name) }
func f3(name string) { go f(name) }
這將輸出(在Go Playground上嘗試):
"with-go" is launched as new
"from-anon-with-go" is launched as new
"from-f3" is launched as new
"with-go-from-f3" is launched as new
注意:基本上所有調(diào)用堆棧的“頂部”都有一個(gè)runtime.goexit()
函數(shù),這是在 goroutine 上運(yùn)行的最頂層函數(shù),也是所有 goroutine 的“退出”點(diǎn)。這就是為什么我們從堆棧中跳過(guò) 3 幀(0. 是runtime.Callers()
它本身,1. 是f()
函數(shù),最后一個(gè)要跳過(guò)的幀是runtime.goexit()
)。您可以在此Go Playground中檢查包含函數(shù)和文件名+行號(hào)的完整調(diào)用堆棧。這不會(huì)改變這個(gè)解決方案的可行性,只是我們必須跳過(guò) 3 幀而不是 2 幀來(lái)判斷是f()
從另一個(gè)函數(shù)調(diào)用還是通過(guò)go
語(yǔ)句調(diào)用。
- 1 回答
- 0 關(guān)注
- 137 瀏覽
添加回答
舉報(bào)