Golang在函數(shù)中得到函數(shù)的調(diào)用棧

這篇文章主要參考了鳥窩的這篇文章趴腋,寫的很好,自己寫一篇防止遺忘

我們在函數(shù)有時想獲取函數(shù)的調(diào)用者信息或是整個調(diào)用棧论咏,這對于日志記錄是很有必要的优炬,但是這些函數(shù)的開銷會很大,使用時需要謹慎厅贪,相關(guān)函數(shù)如下

  • func Caller(skip int) (pc uintptr, file string, line int, ok bool)
  • func Callers(skip int, pc []uintptr) int
  • func CallersFrames(callers []uintptr) *Frames
  • func FuncForPC(pc uintptr) *Func

1. func Caller(skip int) (pc uintptr, file string, line int, ok bool)
這個函數(shù)接收一個skip參數(shù)蠢护,表示調(diào)用的深度,0表示調(diào)用Caller函數(shù)的那個函數(shù)养涮,根據(jù)skip返回四個值葵硕,pc是對應(yīng)函數(shù)的地址,file表示在那個文件单寂,line表示哪行調(diào)用的,ok表示存不存在這個skip對應(yīng)的結(jié)果
演示代碼如下

func main() {
    pc, file, line, ok := runtime.Caller(0)
    println(runtime.FuncForPC(pc).Name(), file, line, ok)
    // main.main D:/Workstation/Goproject/LearningGo//get_function_names_in_go/demo.go 6 true
    // 沒有100層深度的調(diào)用吐辙,所以返回0值
    c, file, line, ok := runtime.Caller(100)
    println(runtime.FuncForPC(pc).Name(), file, line, ok)
   // 0 false 

}

2. func Callers(skip int, pc []uintptr) int
剛剛的Caller只會返回制定skip的調(diào)用信息宣决,這里的Caller可以根據(jù)從你指定的skip開始,將它上面的所以調(diào)用信息獲取出來昏苏,存儲到pc中尊沸,最后返回的int表示獲取到了幾個調(diào)用信息,這里和鳥窩的文章有點不一樣, 鳥窩在文中寫道Callers由于歷史問題贤惯,skip為0時會返回Callers這個函數(shù)本身洼专,所以Callers的1才等于調(diào)用Callers的那個函數(shù),但是我在試的時候發(fā)現(xiàn)Callers這個函數(shù)被重復(fù)了兩遍孵构,不知道為什么屁商,代碼如下

func testCallers() {
    pcs := make([]uintptr, 10)
    n := runtime.Callers(0, pcs)
    for i := 0; i < n; i++ {
        f := runtime.FuncForPC(pcs[i])
        file, line := f.FileLine(pcs[i])
        fmt.Printf("%d %s:%d %s\n", i, file, line, f.Name())
    }
}

func main() {
    Bar()
}

// 下面的這些函數(shù)是為了添加調(diào)用棧的深度
func Bar() {
    Foo()
}

func Foo() {
    testCallers()
}

結(jié)果如下,不知道為什么runtime.Callers出現(xiàn)了一模一樣的兩次


image.png

3. func CallersFrames(callers []uintptr) * Frames
這個函數(shù)接收callers的切片颈墅,表示你想獲取的函數(shù)的地址蜡镶,然后會直接返回這些函數(shù)的信息雾袱,省的去一個個調(diào)用FuncForPC

func testCallersFrames() {
    pc := make([]uintptr, 10) // at least 1 entry needed
    n := runtime.Callers(0, pc)
    frames := runtime.CallersFrames(pc[:n])
    i := 0
    for {
        frame, more := frames.Next()
        fmt.Printf("%d %s:%d %s\n", i, frame.File, frame.Line, frame.Function)
        i++
        if !more {
            break
        }
    }
}

func main() {
    Bar()
}

// 下面的這些函數(shù)是為了添加調(diào)用棧的深度
func Bar() {
    Foo()
}

func Foo() {
    // testCallers()
    testCallersFrames()
}

結(jié)果如下

image.png

4. func FuncForPC(pc uintptr) *Func
FuncForPC 是一個有趣的函數(shù), 它可以把程序計數(shù)器地址對應(yīng)的函數(shù)的信息獲取出來官还。如果因為內(nèi)聯(lián)程序計數(shù)器對應(yīng)多個函數(shù)芹橡,它返回最外面的函數(shù)。

它的返回值是一個*Func類型的值望伦,通過*Func可以獲得函數(shù)地址林说、文件行、函數(shù)名等信息屯伞。

除了上面獲取程序計數(shù)器的方式腿箩,也可以通過反射的方式獲取函數(shù)的地址:

runtime.FuncForPC(reflect.ValueOf(foo).Pointer()).Name()

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市愕掏,隨后出現(xiàn)的幾起案子度秘,更是在濱河造成了極大的恐慌,老刑警劉巖饵撑,帶你破解...
    沈念sama閱讀 216,544評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件剑梳,死亡現(xiàn)場離奇詭異,居然都是意外死亡滑潘,警方通過查閱死者的電腦和手機垢乙,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,430評論 3 392
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來语卤,“玉大人追逮,你說我怎么就攤上這事〈舛妫” “怎么了钮孵?”我有些...
    開封第一講書人閱讀 162,764評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長眼滤。 經(jīng)常有香客問我巴席,道長,這世上最難降的妖魔是什么诅需? 我笑而不...
    開封第一講書人閱讀 58,193評論 1 292
  • 正文 為了忘掉前任漾唉,我火速辦了婚禮,結(jié)果婚禮上堰塌,老公的妹妹穿的比我還像新娘赵刑。我一直安慰自己,他們只是感情好场刑,可當(dāng)我...
    茶點故事閱讀 67,216評論 6 388
  • 文/花漫 我一把揭開白布般此。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪恤煞。 梳的紋絲不亂的頭發(fā)上屎勘,一...
    開封第一講書人閱讀 51,182評論 1 299
  • 那天,我揣著相機與錄音居扒,去河邊找鬼概漱。 笑死,一個胖子當(dāng)著我的面吹牛喜喂,可吹牛的內(nèi)容都是我干的瓤摧。 我是一名探鬼主播,決...
    沈念sama閱讀 40,063評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼玉吁,長吁一口氣:“原來是場噩夢啊……” “哼照弥!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起进副,我...
    開封第一講書人閱讀 38,917評論 0 274
  • 序言:老撾萬榮一對情侶失蹤这揣,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后影斑,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體给赞,經(jīng)...
    沈念sama閱讀 45,329評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,543評論 2 332
  • 正文 我和宋清朗相戀三年矫户,在試婚紗的時候發(fā)現(xiàn)自己被綠了片迅。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,722評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡皆辽,死狀恐怖柑蛇,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情驱闷,我是刑警寧澤耻台,帶...
    沈念sama閱讀 35,425評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站空另,受9級特大地震影響盆耽,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜痹换,卻給世界環(huán)境...
    茶點故事閱讀 41,019評論 3 326
  • 文/蒙蒙 一征字、第九天 我趴在偏房一處隱蔽的房頂上張望都弹。 院中可真熱鬧娇豫,春花似錦、人聲如沸畅厢。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,671評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至浦楣,卻和暖如春袖肥,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背振劳。 一陣腳步聲響...
    開封第一講書人閱讀 32,825評論 1 269
  • 我被黑心中介騙來泰國打工椎组, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人历恐。 一個月前我還...
    沈念sama閱讀 47,729評論 2 368
  • 正文 我出身青樓寸癌,卻偏偏與公主長得像,于是被迫代替她去往敵國和親弱贼。 傳聞我的和親對象是個殘疾皇子蒸苇,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,614評論 2 353

推薦閱讀更多精彩內(nèi)容

  • runtime 包 提供了運行時與系統(tǒng)的交互,比如控制協(xié)程函數(shù),觸發(fā)垃圾立即回收等等底層操作,下面我們就運行時能做...
    酷走天涯閱讀 4,855評論 2 7
  • runtime 包 提供了運行時與系統(tǒng)的交互,比如控制協(xié)程函數(shù)吮旅,觸發(fā)垃圾立即回收等等底層操作,下面我們就運行時能做...
    酷走天涯閱讀 459評論 0 0
  • Golang生成的可執(zhí)行文件在指定平臺即可運行效率很高溪烤,它和C/C++一樣編譯出來的是二進制可執(zhí)行文件,運行Go程...
    JunChow520閱讀 760評論 0 0
  • golang獲取調(diào)用者的方法名及所在源碼行數(shù) 代碼如下參數(shù):skip是要提升的堆棧幀數(shù)庇勃,0-當(dāng)前函數(shù)檬嘀,1-上一層函...
    五歲小孩閱讀 863評論 0 0
  • runtime runtime包提供和go運行時環(huán)境的互操作,如控制go程的函數(shù)匪凉。它也包括用于reflect包的低...
    DevilRoshan閱讀 2,518評論 0 0