函數append
會智能地處理底層數組的容量增加。在切片的容量小於1000個元素時,老是會成倍地增長容量。一旦元素個數超過1000,容量的增加因子就會設爲1.25,
也就是每次增長25%
的容量,隨着語言的演化,這種增加算法可能會有所改變。算法
func main() { l1 := []int{0: 1} k := 1 last := 0 for k < 2000 { l1 = append(l1, k) k++ if cap(l1) != last { fmt.Println(k, cap(l1)) last = cap(l1) } } }
代碼測試數組
func foo(list []int) { for i := 0; i < len(list); i++ { list[i] = 10 + i } return } func main() { list := []int{0, 1, 2} foo(list) fmt.Printf("%v", list) } // 結果 [10, 11, 12]
在64位
架構的機器上,一個切片須要24字節
的內存,指針字段須要8字節
,長度和容量各須要8字節
。安全
*T | (t T) and (t **T)
---
指向T類型的值的
方法集只包含值接收者
聲明的方法。
指向T類型的指針
的方法集包含值接收者
聲明和指針接收者
聲明的方法。架構
go
語言運行時默認會爲每一個可用的物理處理器分配一個邏輯處理器
。
若是建立一個goroutine
並準備運行,這個goroutine
就會被到調度器的全局運行隊列中。以後,調度器就將這些隊列中的goroutine
分配給一個邏輯處理器,並放到這個邏輯處理器對應的本地運行隊列中。併發
邏輯處理器app
本地運行隊列函數
調度器測試
使用go build -race
競爭檢測器標誌來編譯程序
運行程序./go_start.exe
出現警告。ui
能夠使用atomic
和sync
包下的方法或函數保證線程安全atom
unbuffered := make(chan int) buffered := make(chan string, 10)
第一個是無緩衝的通道,第二是有緩衝的通道
任務執行,須要考慮的狀況:
runner自帶超時與中斷功能
type Runner struct { interrupt chan os.Signal complete chan error timeout <-chan time.Time tasks []func(int) } var ErrTimeOut = errors.New("received timeout") var ErrInterrupt = errors.New("received interrupt") // new a Runner func New(d time.Duration) *Runner { return &Runner{ interrupt: make(chan os.Signal, 1), complete: make(chan error), timeout: time.After(d), } } func (r *Runner) Add(tasks ...func(int)) { r.tasks = append(r.tasks, tasks...) } func (r *Runner) Start() error { signal.Notify(r.interrupt, os.Interrupt) go func() { r.complete <- r.run() }() select { case err := <-r.complete: return err case <-r.timeout: return ErrTimeOut } } func (r *Runner) run() error { for id, task := range r.tasks { if r.gotInterrupt() { return ErrInterrupt } task(id) } return nil } func (r *Runner) gotInterrupt() bool { select { case <-r.interrupt: signal.Stop(r.interrupt) return true default: return false } }
資源管理池
package pool import ( "errors" "io" "log" "sync" ) type Pool struct { m sync.Mutex resources chan io.Closer factory func() (io.Closer, error) closed bool } var ErrPoolClosed = errors.New("Pool has been closed") func New(fn func() (io.Closer, error), size uint) (*Pool, error) { if size <= 0 { return nil, errors.New("size value too small") } return &Pool{ factory: fn, resources: make(chan io.Closer, size), }, nil } // get a resource func (p *Pool) Acquire() (io.Closer, error) { select { case r, ok := <-p.resources: log.Println("Acquire:", "shared Resource") if !ok { return nil, ErrPoolClosed } return r, nil default: log.Println("Acquire:", "New Resource") return p.factory() } } // release to reasoure func (p *Pool) Release(r io.Closer) { p.m.Lock() defer p.m.Unlock() if p.closed { r.Close() return } select { case p.resources <- r: log.Println("Release:", "In queue") default: log.Println("Release:", "Closing") r.Close() } } // Close func (p *Pool) Close() { p.m.Lock() defer p.m.Unlock() if p.closed { return } p.closed = true close(p.resources) for r := range p.resources { r.Close() } return }