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 }