Golang 公共變量包——expvar

寫在前面

expvar包是 Golang 官方提供的公共變量包,它可以輔助調(diào)試全局變量荧嵌。支持一些常見的類型:float64慰枕、int64具则、MapString具帮。如果我們的程序要用到上面提的四種類型(其中博肋,Map 類型要求 Key 是字符串)》涮可以考慮使用這個包匪凡。

功能

  1. 它支持對變量的基本操作,修改掘猿、查詢這些锹雏;

  2. 整形類型,可以用來做計數(shù)器术奖;

  3. 操作都是線程安全的礁遵。這點很不錯轻绞。相信大家都自己整過全局變量,除了變量還得整的鎖佣耐,自己寫確實挺麻煩的政勃;

  4. 此外還提供了調(diào)試接口,/debug/vars兼砖。它能夠展示所有通過這個包創(chuàng)建的變量奸远;

  5. 所有的變量都是Var類型,可以自己通過實現(xiàn)這個接口擴(kuò)展其它的類型讽挟;

     type Var interface {
         // String returns a valid JSON value for the variable.
         // Types with String methods that do not return valid JSON
         // (such as time.Time) must not be used as a Var.
         String() string
     }
    
  6. Handler()方法可以得到調(diào)試接口的http.Handler懒叛,和自己的路由對接。

這些基礎(chǔ)的功能就不多說了耽梅,大家可以直接看官方的文檔薛窥。

調(diào)試接口

看源碼的時候發(fā)現(xiàn)一個非常有意思的調(diào)試接口,/debug/vars會把所有注冊的變量打印到接口里面眼姐。這個接口很有情懷诅迷。

func init() {
    http.HandleFunc("/debug/vars", expvarHandler)
    Publish("cmdline", Func(cmdline))
    Publish("memstats", Func(memstats))
}

源碼

var (
    mutex   sync.RWMutex
    vars    = make(map[string]Var)
    varKeys []string // sorted
)
  1. varKeys是全局變量所有的變量名,而且是有序的众旗;

  2. vars根據(jù)變量名保存了對應(yīng)的數(shù)據(jù)罢杉。當(dāng)然mutex就是這個 Map 的鎖;

  3. 這三個變量組合起來其實是一個有序線程安全哈希表的實現(xiàn)贡歧。

     type Var interface {
         // String returns a valid JSON value for the variable.
         // Types with String methods that do not return valid JSON
         // (such as time.Time) must not be used as a Var.
         String() string
     }
     
     type Int struct {
         i int64
     }
    
     func (v *Int) Value() int64 {
         return atomic.LoadInt64(&v.i)
     }
    
     func (v *Int) String() string {
         return strconv.FormatInt(atomic.LoadInt64(&v.i), 10)
     }
    
     func (v *Int) Add(delta int64) {
         atomic.AddInt64(&v.i, delta)
     }
    
     func (v *Int) Set(value int64) {
         atomic.StoreInt64(&v.i, value)
     }
    
  4. 這個包里面的所有類型都實現(xiàn)了這個接口滩租;

  5. 以 Int 類型舉例。實現(xiàn)非常的簡單利朵,注意AddSet方法是線程安全的律想。別的類型實現(xiàn)也一樣

     func Publish(name string, v Var) {
         mutex.Lock()
         defer mutex.Unlock()
         if _, existing := vars[name]; existing {
             log.Panicln("Reuse of exported var name:", name)
         }
         vars[name] = v
         varKeys = append(varKeys, name)
         sort.Strings(varKeys)
     }
     
     func NewInt(name string) *Int {
         v := new(Int)
         Publish(name, v)
         return v
     }
    
  6. 將變量注冊到一開始介紹的varsvarKeys里面;

  7. 注冊時候也是線程安全的哗咆,所有的變量名在注冊的最后排了個序蜘欲;

  8. 創(chuàng)建對象的時候會自動注冊。

     func Do(f func(KeyValue)) {
         mutex.RLock()
         defer mutex.RUnlock()
         for _, k := range varKeys {
             f(KeyValue{k, vars[k]})
         }
     }
    
     func expvarHandler(w http.ResponseWriter, r *http.Request) {
         w.Header().Set("Content-Type", "application/json; charset=utf-8")
         fmt.Fprintf(w, "{\n")
         first := true
         Do(func(kv KeyValue) {
             if !first {
                 fmt.Fprintf(w, ",\n")
             }
             first = false
             fmt.Fprintf(w, "%q: %s", kv.Key, kv.Value)
         })
         fmt.Fprintf(w, "\n}\n")
     }
    
     func Handler() http.Handler {
         return http.HandlerFunc(expvarHandler)
     }
    
  9. Do方法晌柬,利用一個閉包姥份,按照varKeys的順序遍歷所有全局變量;

  10. expvarHandler方法是http.Handler類型年碘,將所有變量通過接口輸出澈歉,里面通過Do方法,把所有變量遍歷了一遍屿衅。挺巧妙埃难;

  11. 通過http.HandleFunc方法把expvarHandler這個外部不可訪問的方法對外,這個方法用于對接自己的路由;

  12. 輸出數(shù)據(jù)的類型涡尘,fmt.Fprintf(w, "%q: %s", kv.Key, kv.Value)忍弛,可以發(fā)現(xiàn),值輸出的字符串考抄,所以輸出的內(nèi)容是String()的結(jié)果细疚。這里有一個技巧,雖然調(diào)用的字符串的方法川梅,但是由于輸出格式%s外面并沒有引號疯兼,所有對于 JSON 來說,輸出的內(nèi)容是對象類型贫途。相當(dāng)于在 JSON 編碼的時候做了一次類型轉(zhuǎn)換吧彪。

     type Func func() interface{}
    
     func (f Func) Value() interface{} {
         return f()
     }
    
     func (f Func) String() string {
         v, _ := json.Marshal(f())
         return string(v)
     }
     
     func cmdline() interface{} {
         return os.Args
     }
    
  13. 這是一個非常有意思的寫法,它可以把任何類型轉(zhuǎn)換成Var類型丢早;

  14. Func定義的是函數(shù)姨裸,它的類型是func() interface{}

  15. Func(cmdline),使用的地方需要看清楚香拉,參數(shù)是cmdline而不是cmdline()啦扬,所以這個寫法是類型轉(zhuǎn)換中狂。轉(zhuǎn)換完之后cmdline方法就有了String()方法凫碌,在String()方法里又調(diào)用了f(),通過 JSON 編碼輸出胃榕。這個小技巧在前面提到的http.HandleFunc里面也有用到盛险,Golang 的程序員對這個是真愛,咱們編碼的時候也要多用用啊勋又。

不足

感覺這個包還是針對簡單變量苦掘,比如整形、字符串這種比較好用楔壤。

  1. 前面已經(jīng)說了鹤啡,Map 類型只支持 Key 是字符串的變量。其它類型還得自己擴(kuò)展蹲嚣,擴(kuò)展的話鎖的問題還是得自己搞递瑰。而且 JSON 編碼低版本不支持 Key 是整形類型的編碼,也是個問題隙畜;
  2. Var接口太簡單抖部,只有一個String()方法,基本上只能輸出變量所有內(nèi)容议惰,別的東西都沒辦法控制慎颗,如果你的變量有10000個鍵值對,那么這個接口基本上屬于不能用。多說一句俯萎,這是 Golang 設(shè)計的常見問題傲宜,比如日志包,輸出的類型是io.Writer夫啊,而這個接口只支持一個方法Write([]byte)蛋哭,想擴(kuò)展日志包的功能很難,這也失去了抽象出來一個接口的意義涮母。
  3. 路由里面還默認(rèn)追加了啟動參數(shù)和MemStats內(nèi)存相關(guān)參數(shù)谆趾。我個人覺得后面這個不應(yīng)該加,調(diào)用runtime.ReadMemStats(stats)會引起 Stop The World叛本,總感覺不值當(dāng)沪蓬。

總結(jié)

看到就寫了,并沒有什么沉淀来候,寫得挺亂的跷叉。這個包很簡單,但是里面還是有些可以借鑒的編碼和設(shè)計营搅。新版本的 Golang 已經(jīng)能解析整形為 Key 的哈希表了云挟,這個包啥時候能跟上支持一下?

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末转质,一起剝皮案震驚了整個濱河市园欣,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌休蟹,老刑警劉巖沸枯,帶你破解...
    沈念sama閱讀 206,723評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異赂弓,居然都是意外死亡绑榴,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,485評論 2 382
  • 文/潘曉璐 我一進(jìn)店門盈魁,熙熙樓的掌柜王于貴愁眉苦臉地迎上來翔怎,“玉大人,你說我怎么就攤上這事杨耙〕嗵祝” “怎么了?”我有些...
    開封第一講書人閱讀 152,998評論 0 344
  • 文/不壞的土叔 我叫張陵按脚,是天一觀的道長于毙。 經(jīng)常有香客問我,道長辅搬,這世上最難降的妖魔是什么唯沮? 我笑而不...
    開封第一講書人閱讀 55,323評論 1 279
  • 正文 為了忘掉前任脖旱,我火速辦了婚禮,結(jié)果婚禮上介蛉,老公的妹妹穿的比我還像新娘萌庆。我一直安慰自己,他們只是感情好币旧,可當(dāng)我...
    茶點故事閱讀 64,355評論 5 374
  • 文/花漫 我一把揭開白布践险。 她就那樣靜靜地躺著,像睡著了一般吹菱。 火紅的嫁衣襯著肌膚如雪巍虫。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,079評論 1 285
  • 那天鳍刷,我揣著相機(jī)與錄音占遥,去河邊找鬼。 笑死输瓜,一個胖子當(dāng)著我的面吹牛瓦胎,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播尤揣,決...
    沈念sama閱讀 38,389評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼搔啊,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了北戏?” 一聲冷哼從身側(cè)響起负芋,我...
    開封第一講書人閱讀 37,019評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎最欠,沒想到半個月后示罗,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體惩猫,經(jīng)...
    沈念sama閱讀 43,519評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡芝硬,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,971評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了轧房。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片拌阴。...
    茶點故事閱讀 38,100評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖奶镶,靈堂內(nèi)的尸體忽然破棺而出迟赃,到底是詐尸還是另有隱情,我是刑警寧澤厂镇,帶...
    沈念sama閱讀 33,738評論 4 324
  • 正文 年R本政府宣布纤壁,位于F島的核電站,受9級特大地震影響捺信,放射性物質(zhì)發(fā)生泄漏酌媒。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,293評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望秒咨。 院中可真熱鬧喇辽,春花似錦、人聲如沸雨席。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,289評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽陡厘。三九已至抽米,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間糙置,已是汗流浹背缨硝。 一陣腳步聲響...
    開封第一講書人閱讀 31,517評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留罢低,地道東北人查辩。 一個月前我還...
    沈念sama閱讀 45,547評論 2 354
  • 正文 我出身青樓,卻偏偏與公主長得像网持,于是被迫代替她去往敵國和親宜岛。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,834評論 2 345

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

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理功舀,服務(wù)發(fā)現(xiàn)萍倡,斷路器,智...
    卡卡羅2017閱讀 134,600評論 18 139
  • SwiftDay011.MySwiftimport UIKitprintln("Hello Swift!")var...
    smile麗語閱讀 3,827評論 0 6
  • 能力模型 選擇題 [primary] 下面屬于關(guān)鍵字的是()A. funcB. defC. structD. cl...
    _張曉龍_閱讀 24,801評論 14 224
  • 械密者:非典型醫(yī)療器械營銷案例 孫易之揉了揉鼻梁辟汰,深吸一口氣列敲,試圖讓心情稍稍平息,然后盯著那條期待許久的公告鏈接帖汞,...
    械密者閱讀 228評論 0 3
  • 我這邊一切都很好戴而,只是少了你,這句話翩蘸,所有異地戀的都會有感觸吧所意。但是很抱歉,今天這篇文章我們不是講異地戀催首。而是講渣...
    420_c644閱讀 262評論 0 0