github.com/haraldrudell/parl@v0.4.176/moderator.go (about) 1 /* 2 © 2020–present Harald Rudell <harald.rudell@gmail.com> (https://haraldrudell.github.io/haraldrudell/) 3 ISC License 4 */ 5 6 package parl 7 8 /* 9 Moderator invokes functions at a limited level of parallelism. 10 It is a ticketing system 11 12 m := NewModerator(20, ctx) 13 m.Do(func() (err error) { // waiting here for a ticket 14 // got a ticket! 15 … 16 return or panic // ticket automatically returned 17 m.String() → waiting: 2(20) 18 */ 19 type Moderator struct { 20 moderatorCore 21 //ctx context.Context 22 } 23 24 // NewModerator creates a cancelable Moderator used to limit parallelism 25 // func NewModerator(parallelism uint64, ctx context.Context) (mo *Moderator) { 26 // return NewModeratorFromCore(NewModeratorCore(parallelism), ctx) 27 // } 28 29 // NewModeratorFromCore allows multiple cancelable Moderators to share 30 // a ModeratorCore ticket pool 31 // func NewModeratorFromCore(mc *ModeratorCore, ctx context.Context) (mo *Moderator) { 32 // if ctx == nil { 33 // panic(perrors.New("NewModerator with nil context")) 34 // } 35 // m := Moderator{ 36 // moderatorCore: moderatorCore{mc}, 37 // ctx: ctx, 38 // } 39 // go m.shutdownThread() 40 // return &m 41 // } 42 43 // func (mo *Moderator) DoErr(fn func() error) (err error) { 44 // if err = mo.getTicket(); err != nil { 45 // return // failed to obtain ticket due to cancelation 46 // } 47 // defer mo.returnTicket() // we will always get a ticket, and it should be returned 48 49 // if fn != nil { 50 // err = fn() 51 // } 52 // return 53 // } 54 55 // // Do calls fn limited by the moderator’s parallelism. 56 // // If the moderator is shut down, ErrModeratorShutdown is returned 57 // func (mo *Moderator) Do(fn func()) { 58 // if err := mo.getTicket(); err != nil { 59 // panic(err) // failed to obtain ticket due to cancelation 60 // } 61 // defer mo.returnTicket() // we will always get a ticket, and it should be returned 62 63 // if fn != nil { 64 // fn() 65 // } 66 // } 67 68 // func (mo *Moderator) getTicket() (err error) { 69 // mo.queue.L.Lock() 70 // defer mo.queue.L.Unlock() 71 72 // isWaiting := false 73 // for { 74 75 // // check for cancelation 76 // if mo.ctx.Err() != nil { 77 // err = mo.ctx.Err() 78 // return // moderator cancelled return 79 // } 80 81 // // check for available ticket 82 // if mo.active < mo.parallelism { 83 // mo.active++ 84 85 // // maintain waiting counter 86 // if isWaiting { 87 // mo.waiting-- 88 // } 89 // return // obtained ticket return 90 // } 91 92 // // maintain waiting counter 93 // if !isWaiting { 94 // isWaiting = true 95 // mo.waiting++ 96 // } 97 98 // // block until cond.Notify or cond.Broadcast 99 // mo.queue.Wait() 100 // } 101 // } 102 103 // func (mo *Moderator) shutdownThread() { 104 // <-mo.ctx.Done() 105 // mo.queue.Broadcast() 106 // } 107 108 // func (mo *Moderator) Status() (parallelism uint64, active uint64, waiting uint64, isShutdown bool) { 109 // parallelism, active, waiting = mo.moderatorCore.Status() 110 // isShutdown = mo.ctx.Err() != nil 111 // return 112 // } 113 114 // func (mo *Moderator) String() (s string) { 115 // s = mo.moderatorCore.String() 116 // if mo.ctx.Err() != nil { 117 // s += " shutdown" 118 // } 119 // return 120 // }