Golang 公開變數包——expvar

來源:互聯網
上載者:User
這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。

寫在前面

expvar包是 Golang 官方提供的公開變數包,它可以輔助調試全域變數。支援一些常見的類型:float64int64MapString。如果我們的程式要用到上面提的四種類型(其中,Map 類型要求 Key 是字串)。可以考慮使用這個包。

功能

  1. 它支援對變數的基本操作,修改、查詢這些;
  2. 整形類型,可以用來做計數器;
  3. 操作都是安全執行緒的。這點很不錯。相信大家都自己整過全域變數,除了變數還得整的鎖,自己寫確實挺麻煩的;
  4. 此外還提供了調試介面,/debug/vars。它能夠展示所有通過這個包建立的變數;
  5. 所有的變數都是Var類型,可以自己通過實現這個介面擴充其它的類型;

     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()方法可以得到調試介面的http.Handler,和自己的路由對接。

這些基礎的功能就不多說了,大家可以直接看官方的文檔。

調試介面

看源碼的時候發現一個非常有意思的調試介面,/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根據變數名儲存了對應的資料。當然mutex就是這個 Map 的鎖;
  3. 這三個變數組合起來其實是一個有序安全執行緒雜湊表的實現。

     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) }
  1. 這個包裡面的所有類型都實現了這個介面;
  2. 以 Int 類型舉例。實現非常的簡單,注意AddSet方法是安全執行緒的。別的類型實現也一樣

     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 }
  3. 將變數註冊到一開始介紹的varsvarKeys裡面;

  4. 註冊時候也是安全執行緒的,所有的變數名在註冊的最後排了個序;
  5. 建立對象的時候會自動註冊。

     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) }
  6. Do方法,利用一個閉包,按照varKeys的順序遍曆所有全域變數;

  7. expvarHandler方法是http.Handler類型,將所有變數通過介面輸出,裡面通過Do方法,把所有變數遍曆了一遍。挺巧妙;
  8. 通過http.HandleFunc方法把expvarHandler這個外部不可訪問的方法對外,這個方法用於對接自己的路由;
  9. 輸出資料的類型,fmt.Fprintf(w, "%q: %s", kv.Key, kv.Value),可以發現,值輸出的字串,所以輸出的內容是String()的結果。這裡有一個技巧,雖然調用的字串的方法,但是由於輸出格式%s外面並沒有引號,所有對於 JSON 來說,輸出的內容是物件類型。相當於在 JSON 編碼的時候做了一次類型轉換。

     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 }
  10. 這是一個非常有意思的寫法,它可以把任何類型轉換成Var類型;

  11. Func定義的是函數,它的類型是func() interface{}
  12. Func(cmdline),使用的地方需要看清楚,參數是cmdline而不是cmdline(),所以這個寫法是類型轉換。轉換完之後cmdline方法就有了String()方法,在String()方法裡又調用了f(),通過 JSON 編碼輸出。這個小技巧在前面提到的http.HandleFunc裡面也有用到,Golang 的程式員對這個是真愛,咱們編碼的時候也要多用用啊。

不足

感覺這個包還是針對簡單變數,比如整形、字串這種比較好用。

  1. 前面已經說了,Map 類型只支援 Key 是字串的變數。其它類型還得自己擴充,擴充的話鎖的問題還是得自己搞。而且 JSON 編碼低版本不支援 Key 是整形類型的編碼,也是個問題;
  2. Var介面太簡單,只有一個String()方法,基本上只能輸出變數所有內容,別的東西都沒辦法控制,如果你的變數有10000個索引值對,那麼這個介面基本上屬於不能用。多說一句,這是 Golang 設計的常見問題,比如日誌包,輸出的類型是io.Writer,而這個介面只支援一個方法Write([]byte),想擴充日誌包的功能很難,這也失去了抽象出來一個介面的意義。
  3. 路由裡面還預設追加了啟動參數和MemStats記憶體相關參數。我個人覺得後面這個不應該加,調用runtime.ReadMemStats(stats)會引起 Stop The World,總感覺不值當。

總結

看到就寫了,並沒有什麼沉澱,寫得挺亂的。這個包很簡單,但是裡面還是有些可以借鑒的編碼和設計。新版本的 Golang 已經能解析整形為 Key 的雜湊表了,這個包啥時候能跟上支援一下?

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.