函数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 }