github.com/zhongdalu/gf@v1.0.0/g/os/grpool/grpool.go (about)

     1  // Copyright 2017-2019 gf Author(https://github.com/zhongdalu/gf). 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/zhongdalu/gf.
     6  
     7  // Package grpool implements a goroutine reusable pool.
     8  package grpool
     9  
    10  import (
    11  	"errors"
    12  
    13  	"github.com/zhongdalu/gf/g/container/glist"
    14  	"github.com/zhongdalu/gf/g/container/gtype"
    15  )
    16  
    17  // Goroutine Pool
    18  type Pool struct {
    19  	limit  int         // Max goroutine count limit.
    20  	count  *gtype.Int  // Current running goroutine count.
    21  	list   *glist.List // Job list for asynchronous job adding purpose.
    22  	closed *gtype.Bool // Is pool closed or not.
    23  }
    24  
    25  // Default goroutine pool.
    26  var pool = New()
    27  
    28  // New creates and returns a new goroutine pool object.
    29  // The parameter <limit> is used to limit the max goroutine count,
    30  // which is not limited in default.
    31  func New(limit ...int) *Pool {
    32  	p := &Pool{
    33  		limit:  -1,
    34  		count:  gtype.NewInt(),
    35  		list:   glist.New(),
    36  		closed: gtype.NewBool(),
    37  	}
    38  	if len(limit) > 0 && limit[0] > 0 {
    39  		p.limit = limit[0]
    40  	}
    41  	return p
    42  }
    43  
    44  // Add pushes a new job to the pool using default goroutine pool.
    45  // The job will be executed asynchronously.
    46  func Add(f func()) error {
    47  	return pool.Add(f)
    48  }
    49  
    50  // Size returns current goroutine count of default goroutine pool.
    51  func Size() int {
    52  	return pool.Size()
    53  }
    54  
    55  // Jobs returns current job count of default goroutine pool.
    56  func Jobs() int {
    57  	return pool.Jobs()
    58  }
    59  
    60  // Add pushes a new job to the pool.
    61  // The job will be executed asynchronously.
    62  func (p *Pool) Add(f func()) error {
    63  	for p.closed.Val() {
    64  		return errors.New("pool closed")
    65  	}
    66  	p.list.PushFront(f)
    67  	var n int
    68  	for {
    69  		n = p.count.Val()
    70  		if p.limit != -1 && n >= p.limit {
    71  			return nil
    72  		}
    73  		if p.count.Cas(n, n+1) {
    74  			break
    75  		}
    76  	}
    77  	p.fork()
    78  	return nil
    79  }
    80  
    81  // Cap returns the capacity of the pool.
    82  // This capacity is defined when pool is created.
    83  // If it returns -1 means no limit.
    84  func (p *Pool) Cap() int {
    85  	return p.limit
    86  }
    87  
    88  // Size returns current goroutine count of the pool.
    89  func (p *Pool) Size() int {
    90  	return p.count.Val()
    91  }
    92  
    93  // Jobs returns current job count of the pool.
    94  func (p *Pool) Jobs() int {
    95  	return p.list.Size()
    96  }
    97  
    98  // fork creates a new goroutine pool.
    99  func (p *Pool) fork() {
   100  	go func() {
   101  		defer p.count.Add(-1)
   102  		job := (interface{})(nil)
   103  		for !p.closed.Val() {
   104  			if job = p.list.PopBack(); job != nil {
   105  				job.(func())()
   106  			} else {
   107  				return
   108  			}
   109  		}
   110  	}()
   111  }
   112  
   113  // IsClosed returns if pool is closed.
   114  func (p *Pool) IsClosed() bool {
   115  	return p.closed.Val()
   116  }
   117  
   118  // Close closes the goroutine pool, which makes all goroutines exit.
   119  func (p *Pool) Close() {
   120  	p.closed.Set(true)
   121  }