golang 并发demo
package utils import ( "sync" ) type GoLimit struct { max uint //并发最大数量 count uint //当前已有并发数 isAddLock bool //是否已锁定增加 zeroChan chan interface{} //为0时广播 addLock sync.Mutex //(增加并发数的)锁 dataLock sync.Mutex //(修改数据的)锁 } func NewGoLimit(max uint) *GoLimit { return &GoLimit{max: max, count: 0, isAddLock: false, zeroChan: nil} } //并发计数加1.若 计数>=max_num, 则阻塞,直到 计数<max_num func (g *GoLimit) Add() { g.addLock.Lock() g.dataLock.Lock() g.count += 1 if g.count < g.max { //未超并发时解锁,后续可以继续增加 g.addLock.Unlock() } else { //已到最大并发数, 不解锁并标记. 等数量减少后解锁 g.isAddLock = true } g.dataLock.Unlock() } //并发计数减1 //若计数<max_num, 可以使原阻塞的Add()快速解除阻塞 func (g *GoLimit) Done() { g.dataLock.Lock() g.count -= 1 //解锁 if g.isAddLock == true && g.count < g.max { g.isAddLock = false g.addLock.Unlock() } //0广播 if g.count == 0 && g.zeroChan != nil { close(g.zeroChan) g.zeroChan = nil } g.dataLock.Unlock() } //更新最大并发计数为, 若是调大, 可以使原阻塞的Add()快速解除阻塞 func (g *GoLimit) SetMax(n uint) { g.dataLock.Lock() g.max = n //解锁 if g.isAddLock == true && g.count < g.max { g.isAddLock = false g.addLock.Unlock() } //加锁 if g.isAddLock == false && g.count >= g.max { g.isAddLock = true g.addLock.Lock() } g.dataLock.Unlock() } //若当前并发计数为0, 则快速返回; 否则阻塞等待,直到并发计数为0 func (g *GoLimit) WaitZero() { g.dataLock.Lock() //无需等待 if g.count == 0 { g.dataLock.Unlock() return } //无广播通道, 创建一个 if g.zeroChan == nil { g.zeroChan = make(chan interface{}) } //复制通道后解锁, 避免从nil读数据 c := g.zeroChan g.dataLock.Unlock() <-c } //获取并发计数 func (g *GoLimit) Count() uint { return g.count } //获取最大并发计数 func (g *GoLimit) Max() uint { return g.max }
调用:
g := utils.NewGoLimit(10) //max_num(最大允许并发数)设置为10 for k, v := range filePaths { g.Add() go func(g *utils.GoLimit,k int,v string) { defer g.Done() //并发计数减1 p.PostFile(v, url, map[string]string{"guid": guid, "chunk": cast.ToString(k)}) }(g,k,v) } g.WaitZero() //阻塞, 直到所有并发都完成