github.com/TeaOSLab/EdgeNode@v1.3.8/internal/utils/fs/limiter.go (about)

     1  // Copyright 2024 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn .
     2  
     3  package fsutils
     4  
     5  import (
     6  	"runtime"
     7  	"time"
     8  )
     9  
    10  var maxThreads = runtime.NumCPU()
    11  var WriterLimiter = NewLimiter(max(maxThreads, 8))
    12  var ReaderLimiter = NewLimiter(max(maxThreads, 8))
    13  
    14  type Limiter struct {
    15  	threads      chan struct{}
    16  	count        int
    17  	countDefault int
    18  	timers       chan *time.Timer
    19  }
    20  
    21  func NewLimiter(threads int) *Limiter {
    22  	if threads < 4 {
    23  		threads = 4
    24  	}
    25  	if threads > 64 {
    26  		threads = 64
    27  	}
    28  
    29  	var threadsChan = make(chan struct{}, threads)
    30  	for i := 0; i < threads; i++ {
    31  		threadsChan <- struct{}{}
    32  	}
    33  
    34  	return &Limiter{
    35  		countDefault: threads,
    36  		count:        threads,
    37  		threads:      threadsChan,
    38  		timers:       make(chan *time.Timer, 4096),
    39  	}
    40  }
    41  
    42  func (this *Limiter) SetThreads(newThreads int) {
    43  	if newThreads <= 0 {
    44  		newThreads = this.countDefault
    45  	}
    46  
    47  	if newThreads != this.count {
    48  		var threadsChan = make(chan struct{}, newThreads)
    49  		for i := 0; i < newThreads; i++ {
    50  			threadsChan <- struct{}{}
    51  		}
    52  
    53  		this.threads = threadsChan
    54  		this.count = newThreads
    55  	}
    56  }
    57  
    58  func (this *Limiter) Ack() {
    59  	<-this.threads
    60  }
    61  
    62  func (this *Limiter) TryAck() bool {
    63  	const timeoutDuration = 500 * time.Millisecond
    64  
    65  	var timeout *time.Timer
    66  	select {
    67  	case timeout = <-this.timers:
    68  		timeout.Reset(timeoutDuration)
    69  	default:
    70  		timeout = time.NewTimer(timeoutDuration)
    71  	}
    72  
    73  	defer func() {
    74  		timeout.Stop()
    75  
    76  		select {
    77  		case this.timers <- timeout:
    78  		default:
    79  		}
    80  	}()
    81  
    82  	select {
    83  	case <-this.threads:
    84  		return true
    85  	case <-timeout.C:
    86  		return false
    87  	}
    88  }
    89  
    90  func (this *Limiter) Release() {
    91  	select {
    92  	case this.threads <- struct{}{}:
    93  	default:
    94  		// 由于容量可能有变化,这里忽略多余的thread
    95  	}
    96  }
    97  
    98  func (this *Limiter) FreeThreads() int {
    99  	return len(this.threads)
   100  }