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  // }