github.com/rolandhe/saber@v0.0.4/gocc/defaultExecutor.go (about)

     1  // Golang concurrent tools like java juc.
     2  //
     3  // Copyright 2023 The saber Authors. All rights reserved.
     4  //
     5  
     6  package gocc
     7  
     8  import (
     9  	"time"
    10  )
    11  
    12  // NewDefaultExecutor 构建指定并发任务量的任务执行器
    13  //
    14  //	concurLevel  可以并发执行的任务总量
    15  func NewDefaultExecutor(concurLevel uint) Executor {
    16  	return &chanExecutor{
    17  		concurLevel:     concurLevel,
    18  		concurrentLimit: NewDefaultSemaphore(concurLevel),
    19  	}
    20  }
    21  
    22  // Task 需要执行的任务主体,它是包含任务业务逻辑的函数
    23  type Task func() (any, error)
    24  
    25  // Executor 多任务执行器
    26  type Executor interface {
    27  
    28  	// Execute 执行任务,如果执行器内资源已耗尽,则直接返回nil,false,否则返回future和true
    29  	Execute(task Task) (*Future, bool)
    30  
    31  	// ExecuteTimeout 执行任务,支持超时,如果执行器内资源已耗尽且在超时时间内依然不能获取到资源,则返回nil,false,如果执行器内有资源或者超时时间内能获取资源,返回future,true
    32  	ExecuteTimeout(task Task, timeout time.Duration) (*Future, bool)
    33  
    34  	// ExecuteInGroup 与Execute类似,只是返回的future会被加到FutureGroup中, 可以使用FutureGroup来管理批量的任务:
    35  	//
    36  	//1. 主线程在FutureGroup上等待多个任务完成,没有必要自己循环扫描多个Future
    37  	//
    38  	//2. 从FutureGroup中拿出多个Future,不需要自己维护
    39  	ExecuteInGroup(task Task, g *FutureGroup) (*Future, bool)
    40  	
    41  	// ExecuteInGroupTimeout 与ExecuteTimeout类似,只是增加了FutureGroup
    42  	ExecuteInGroupTimeout(task Task, g *FutureGroup, timeout time.Duration) (*Future, bool)
    43  }
    44  
    45  type taskResult struct {
    46  	r any
    47  	e error
    48  }
    49  
    50  type chanExecutor struct {
    51  	concurLevel     uint
    52  	concurrentLimit Semaphore
    53  }
    54  
    55  func (et *chanExecutor) Execute(task Task) (*Future, bool) {
    56  	if !acquireToken(et.concurrentLimit, 0) {
    57  		return nil, false
    58  	}
    59  	future := newFuture()
    60  	go runTask(task, future, et.concurrentLimit)
    61  
    62  	return future, true
    63  }
    64  
    65  func (et *chanExecutor) ExecuteTimeout(task Task, timeout time.Duration) (*Future, bool) {
    66  	if !acquireToken(et.concurrentLimit, timeout) {
    67  		return nil, false
    68  	}
    69  	future := newFuture()
    70  	go runTask(task, future, et.concurrentLimit)
    71  
    72  	return future, true
    73  }
    74  
    75  func (et *chanExecutor) ExecuteInGroup(task Task, g *FutureGroup) (*Future, bool) {
    76  	if !acquireToken(et.concurrentLimit, 0) {
    77  		return nil, false
    78  	}
    79  	future := newFutureWithGroup(g)
    80  	go runTask(task, future, et.concurrentLimit)
    81  	return future, true
    82  }
    83  
    84  func (et *chanExecutor) ExecuteInGroupTimeout(task Task, g *FutureGroup, timeout time.Duration) (*Future, bool) {
    85  	if !acquireToken(et.concurrentLimit, timeout) {
    86  		return nil, false
    87  	}
    88  
    89  	future := newFutureWithGroup(g)
    90  	go runTask(task, future, et.concurrentLimit)
    91  	return future, true
    92  }
    93  
    94  func runTask(task Task, future *Future, concurrentLimit Semaphore) {
    95  	var r any
    96  	var err = TaskCancelledError
    97  	if !future.IsCancelled() {
    98  		r, err = task()
    99  	}
   100  
   101  	future.accept(&taskResult{r, err})
   102  	concurrentLimit.Release()
   103  }
   104  
   105  func acquireToken(concurrentLimit Semaphore, timeout time.Duration) bool {
   106  	if timeout == 0 {
   107  		if !concurrentLimit.TryAcquire() {
   108  			return false
   109  		}
   110  	} else {
   111  		if !concurrentLimit.AcquireTimeout(timeout) {
   112  			return false
   113  		}
   114  	}
   115  	return true
   116  }