Go最佳實務

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

來自NSQ

nsq的官方文檔的Dsign中提到一個PPThttps://speakerdeck.com/snakes/nsq-nyc-golang-meetup, 裡面有這樣一段話

總結一下.

  1. don’t be afraid of sync package
    sync包裡有
  • sync.Mutex(互斥鎖,一讀一寫)
  • sync.RWMutex(讀寫鎖,可以多讀一寫)
  • sync.Pool(對象池, 合理利用可以減少記憶體配置, 降低GC壓力, 稍後寫一篇部落格說說)
  • sync.Once(並發控制. 適用於開幾個goroutines去執行一個只執行一次的任務, 比如單例模式)
  • sync.Cond(並發控制, cond.Wait()阻塞至其他goroutie運行到cond.Signal())
  • sync.WaitGroup(並發控制. 通常用法 wg.Add增加任務數量 goroutie完成任務後執行wg.Done,任務數量減1 wg.Wait等待wg任務數量為0)
  1. goroutines are cheap not free
    這句話在其他地方也看過, go func()簡單好用, 建立開銷也很小, 但也是有開銷的. 很多情況下開固定數量worker, 用channel傳遞資料, 效果會更好.
    go-apns2中的example是個非常好的例子.https://github.com/sideshow/apns2/blob/master/_example/channel/main.go

注意一個問題, go裡面一個goroutine panic了, 會導致進程退出, 所以go func()時第一行帶上

go func(){defer func(){if err:=recover(); err!=nil{}}()}()

是安全的做法, worker channel法時類似

package mainimport ("fmt""log""time")func main() {ch := make(chan int, 10)for i := 0; i < 2; i++ {go worker(ch, i)}for i := 0; i < 3; i++ {ch <- ich <- -1}time.Sleep(time.Second * 5)}func worker(ch <-chan int, goId int) {defer func(ch <-chan int) {if err := recover(); err != nil {log.Printf("worker%d recover error:%s", goId, err)go worker(ch, goId)}}(ch)log.Printf("worker%d running", goId)for data := range ch {log.Printf("worker%d received data:%d", goId, data)if data == -1 {panic(fmt.Errorf("worker%d panic", goId))}}}

fasthttp之所以快, 其中一個原因就是net/http是來一個串連就建立一個goroutie, 而fasthttp用了池複用了goroutines.

  1. watch your allocations (string() is costly, re-user buffers)
    go裡面 []byte和string互轉是會發生複製的, 開銷明顯, 如果代碼裡頻繁互轉, 考慮使用bytes.buffer 和 sync.Pool

  2. use anonymous structs for arbitrary JSON
    在寫http api時, parse body這種事情, 如果只是純粹取body裡的json資料, 沒必要單獨定義結構體, 在函數裡定義一個匿名結構體就好. var s struct { A int}

  3. no built-in per-request HTTP timeouts
    這是說要注意預設的httpClient沒有逾時

  4. synchronizing goroutine exit is hard - log each cleanup step in long-running goroutines
    同步化的goroutine一不小心就沒有退出, 如果你寫一個長期啟動並執行服務, 用logger記錄每一個goroutine的清理退出, 防止goroutine泄露

  5. select skips nil channels

select語句是會跳過nil的channels的. 因為在Go裡往已經close掉的channel裡發送資料是會panic的, 可以利用select語句.
附: channel操作導致panic的情況有: 關閉一個nil的channel, 關閉一個已經關閉的channel( j,ok:= <- ch, ok為false時代表ch已經關閉了), 往一個已經關閉的channel裡發送資料(從已經關閉的channel裡讀資料是OK的, 如果這個channel是帶緩衝的, 那麼可以讀到所有資料)

來自GO箴言

Python有import this的zen of Python, 想不到Go也有箴言
https://speakerdeck.com/ajstarks/go-proverbs

  1. 在go裡, goroutines之間通訊不要用共用記憶體的方式實現, 應該用channel來實現
  2. 並發不是並行
  3. channel是編排, mutexs是串列
  4. interface定義越多的方法, 抽象程度越低. Go提倡用介面組合的方式實現更大的介面
  5. 零值, 猜測這裡說的是struct{}吧, struct{}是一個不佔記憶體的空結構體, 在用map實現set, channel發送無額外意義的signal時能降低記憶體配置
  6. 提倡gofmt
  7. 一點點複製比一點點依賴好. 官方包裡有時能見到一些複製的代碼, 這是為了不互相依賴
  8. syscall每個平台實現不一樣, 要加build tags
  9. cgo每個平台的lib不一樣, 要加build tags
  10. Cgo不是go
  11. unsafe包不提供保障
  12. 簡潔勝過高效
  13. error是值 可以用值的方式去處理錯誤: 傳遞, 比較
  14. 不用僅檢查錯誤, 要優雅地處理
  15. 多花精力設計架構, 模組命名, 寫詳細的文檔
  16. 寫良好的文檔給使用者
  17. 對於普通錯誤, 應該用多值返回錯誤, 而不是手動panic

未知來源

  1. 寫可重複使用的函數, 接收介面類型, 返回具體類型

Golang Github

https://github.com/golang/go/wiki/CodeReviewComments

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.