Golang常見的坑筆記

Golang 介紹及踩坑系列之三git

Golang奇葩點(坑2)github

筆記

List的遍歷刪除

由於是指針因此要先將指針指到下一個元素再刪。併發

錯誤寫法(簡潔,漂亮,可是。。。):
for e := l.Front(); e != nil; e = e.Next() {
	l.Remove(e)
}

正確寫法
var next *Element
for e := l.Front(); e != nil; e = next {
	next = e.Next()
	l.Remove(e)
}


// 看看具體實現代碼(container/list.go)
func (l *List) remove(e *Element) *Element {
	e.prev.next = e.next //當前元素前一個元素指向當前的下一個元素
	e.next.prev = e.prev //當前元素下一個元素的上一個元素是當前元素的上一個元素
	e.next = nil // avoid memory leaks  釋放指針
	e.prev = nil // avoid memory leaks
	e.list = nil
	l.len--
	return e
}

時間問題

Format 的時候 時間必須是 2006-01-02 15:04:05 ,奇葩時間。dom

緣由:
這裏寫死了(time/format.go)
const (
	ANSIC       = "Mon Jan _2 15:04:05 2006"
	UnixDate    = "Mon Jan _2 15:04:05 MST 2006"
	RubyDate    = "Mon Jan 02 15:04:05 -0700 2006"
	RFC822      = "02 Jan 06 15:04 MST"
	RFC3339     = "2006-01-02T15:04:05Z07:00"
	……
)

range

values := []string{"a", "b", "c"}
for _, v := range values {
	go func() {
		fmt.Println(v)
	}()
}
time.Sleep(2*time.Second)
fmt.Println("end")
	    
輸出三個c,而不是順序的a, b, c

//查找錯誤
values := []string{"a", "b", "c"}
for _, v := range values {   //(1)
	go func() {    //(2)
		fmt.Println(v)   //隱式用v的地址傳遞
	}()
}
(1)複用了臨時變量,只有一個臨時變量的空間
(2) 只是goroutine放到調度隊列,不是馬上運行,還要排隊先,等排到本身的時候,黃花菜已經涼了


解決
for _, v := range values {
	go func(u string) {
		fmt.Println(u)
	}(v)  //明確值複製,做爲棧變量
}

相似的
list := make(map[int]*Link)
for _, lnk := range linktree {
       list[lnk.Code] = &lnk
}

解決
list := make(map[int]*Link)
for _, lnk := range linktree {
        var lnk = linktree
       list[lnk.Code] = &lnk 
}

Channel的喚醒時序

當多個channel都處於就緒狀態時,激活的channel是隨機的性能

A Tour of Go: A select blocks until one of its cases can run, then it executes that case. It chooses one at random if multiple are ready設計

切勿想固然的認爲先來後到指針

queue

Golang沒有直接的queuecode

能夠預期queue長度的狀況下用channelorm

沒法預期長度是用list看成隊列用對象

也能夠根據實際狀況,將list做爲channel的二級隊列(sometimes you may need it)

解決方案:

  1. 須要嚴格順序處理的都放入一個channel
  2. 設計系統時須要仔細考慮時序的影響,特別是併發環境下

避免大對象拷貝

1.若是map的value較大,一般應該使用指針來存儲,以免性能問題,相似的還有channel,slice等

2.避免[]byte和string的反覆來回轉換

一個簡單的池

func (p *ConnectionPool) InitPool(size int, f FactoryMethod) {
	p.conn = make(chan interface{}, size)
	for i := 0; i < size; i++ {
		p.conn <-  f()
	}
	p.size = size
}

func (p *ConnectionPool) Get() interface{} {
	return <-p.conn
}

func (p *ConnectionPool) Put(conn interface{}) {
	p.conn <- conn
}
相關文章
相關標籤/搜索