semaphore
带权重的信号量在Golang中提供了一种灵活的机制,用于管理对共享资源的并发访问。通过合理使用带权重的信号量,可以更好地平衡并发访问和资源使用,从而提高程序的性能和稳定性
数据结构
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| type waiter struct { n int64 ready chan<- struct{} }
type Weighted struct { size int64 cur int64 mu sync.Mutex waiters list.List }
|
方法列表
1 2 3 4 5 6 7 8 9
| func NewWeighted(n int64) *Weighted
func (s *Weighted) Acquire(ctx context.Context, n int64) error
func (s *Weighted) Release(n int64)
func (s *Weighted) TryAcquire(n int64) bool
|
Acquire 和 TryAcquire
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78
| func (s *Weighted) Acquire(ctx context.Context, n int64) error { s.mu.Lock() if s.size-s.cur >= n && s.waiters.Len() == 0 { s.cur += n s.mu.Unlock() return nil } if n > s.size { s.mu.Unlock() <-ctx.Done() return ctx.Err() } ready := make(chan struct{}) w := waiter{n: n, ready: ready} elem := s.waiters.PushBack(w) s.mu.Unlock()
select { case <-ctx.Done(): err := ctx.Err() s.mu.Lock() select { case <-ready: err = nil default: isFront := s.waiters.Front() == elem s.waiters.Remove(elem) if isFront && s.size > s.cur { s.notifyWaiters() } } s.mu.Unlock() return err case <-ready: return nil } }
func (s *Weighted) TryAcquire(n int64) bool { s.mu.Lock() success := s.size-s.cur >= n && s.waiters.Len() == 0 if success { s.cur += n } s.mu.Unlock() return success }
func (s *Weighted) notifyWaiters() { for { next := s.waiters.Front() if next == nil { break } w := next.Value.(waiter) if s.size-s.cur < w.n { break } s.cur += w.n s.waiters.Remove(next) close(w.ready) } }
|
Release
1 2 3 4 5 6 7 8 9 10 11 12
| func (s *Weighted) Release(n int64) { s.mu.Lock() s.cur -= n if s.cur < 0 { s.mu.Unlock() panic("semaphore: released more than held") } s.notifyWaiters() s.mu.Unlock() }
|