github.com/gogf/gf/v2@v2.7.4/os/grpool/grpool_pool.go (about)

     1  // Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
     2  //
     3  // This Source Code Form is subject to the terms of the MIT License.
     4  // If a copy of the MIT was not distributed with this file,
     5  // You can obtain one at https://github.com/gogf/gf.
     6  
     7  package grpool
     8  
     9  import (
    10  	"context"
    11  
    12  	"github.com/gogf/gf/v2/errors/gcode"
    13  	"github.com/gogf/gf/v2/errors/gerror"
    14  )
    15  
    16  // Add pushes a new job to the pool.
    17  // The job will be executed asynchronously.
    18  func (p *Pool) Add(ctx context.Context, f Func) error {
    19  	for p.closed.Val() {
    20  		return gerror.NewCode(
    21  			gcode.CodeInvalidOperation,
    22  			"goroutine defaultPool is already closed",
    23  		)
    24  	}
    25  	p.list.PushFront(&localPoolItem{
    26  		Ctx:  ctx,
    27  		Func: f,
    28  	})
    29  	// Check and fork new worker.
    30  	p.checkAndForkNewGoroutineWorker()
    31  	return nil
    32  }
    33  
    34  // AddWithRecover pushes a new job to the pool with specified recover function.
    35  //
    36  // The optional `recoverFunc` is called when any panic during executing of `userFunc`.
    37  // If `recoverFunc` is not passed or given nil, it ignores the panic from `userFunc`.
    38  // The job will be executed asynchronously.
    39  func (p *Pool) AddWithRecover(ctx context.Context, userFunc Func, recoverFunc RecoverFunc) error {
    40  	return p.Add(ctx, func(ctx context.Context) {
    41  		defer func() {
    42  			if exception := recover(); exception != nil {
    43  				if recoverFunc != nil {
    44  					if v, ok := exception.(error); ok && gerror.HasStack(v) {
    45  						recoverFunc(ctx, v)
    46  					} else {
    47  						recoverFunc(ctx, gerror.NewCodef(gcode.CodeInternalPanic, "%+v", exception))
    48  					}
    49  				}
    50  			}
    51  		}()
    52  		userFunc(ctx)
    53  	})
    54  }
    55  
    56  // Cap returns the capacity of the pool.
    57  // This capacity is defined when pool is created.
    58  // It returns -1 if there's no limit.
    59  func (p *Pool) Cap() int {
    60  	return p.limit
    61  }
    62  
    63  // Size returns current goroutine count of the pool.
    64  func (p *Pool) Size() int {
    65  	return p.count.Val()
    66  }
    67  
    68  // Jobs returns current job count of the pool.
    69  // Note that, it does not return worker/goroutine count but the job/task count.
    70  func (p *Pool) Jobs() int {
    71  	return p.list.Size()
    72  }
    73  
    74  // IsClosed returns if pool is closed.
    75  func (p *Pool) IsClosed() bool {
    76  	return p.closed.Val()
    77  }
    78  
    79  // Close closes the goroutine pool, which makes all goroutines exit.
    80  func (p *Pool) Close() {
    81  	p.closed.Set(true)
    82  }
    83  
    84  // checkAndForkNewGoroutineWorker checks and creates a new goroutine worker.
    85  // Note that the worker dies if the job function panics and the job has no recover handling.
    86  func (p *Pool) checkAndForkNewGoroutineWorker() {
    87  	// Check whether fork new goroutine or not.
    88  	var n int
    89  	for {
    90  		n = p.count.Val()
    91  		if p.limit != -1 && n >= p.limit {
    92  			// No need fork new goroutine.
    93  			return
    94  		}
    95  		if p.count.Cas(n, n+1) {
    96  			// Use CAS to guarantee atomicity.
    97  			break
    98  		}
    99  	}
   100  
   101  	// Create job function in goroutine.
   102  	go p.asynchronousWorker()
   103  }
   104  
   105  func (p *Pool) asynchronousWorker() {
   106  	defer p.count.Add(-1)
   107  
   108  	var (
   109  		listItem interface{}
   110  		poolItem *localPoolItem
   111  	)
   112  	// Harding working, one by one, job never empty, worker never die.
   113  	for !p.closed.Val() {
   114  		listItem = p.list.PopBack()
   115  		if listItem == nil {
   116  			return
   117  		}
   118  		poolItem = listItem.(*localPoolItem)
   119  		poolItem.Func(poolItem.Ctx)
   120  	}
   121  }