You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
61 lines
1.3 KiB
61 lines
1.3 KiB
package operation
|
|
|
|
import (
|
|
"reflect"
|
|
"runtime"
|
|
"sync"
|
|
"sync/atomic"
|
|
)
|
|
|
|
type OperationRequest func()
|
|
|
|
var (
|
|
requestSlots = uint32(32)
|
|
requests = make([]chan OperationRequest, requestSlots) // increase slots to increase fairness
|
|
ConcurrentUploadLimit = int32(runtime.NumCPU()) // directly related to memory usage
|
|
concurrentLimitCond = sync.NewCond(new(sync.Mutex))
|
|
concurrentUpload int32
|
|
)
|
|
|
|
func init() {
|
|
|
|
for i := 0; i < int(requestSlots); i++ {
|
|
requests[i] = make(chan OperationRequest)
|
|
}
|
|
|
|
cases := make([]reflect.SelectCase, requestSlots)
|
|
for i, ch := range requests {
|
|
cases[i] = reflect.SelectCase{Dir: reflect.SelectRecv, Chan: reflect.ValueOf(ch)}
|
|
}
|
|
|
|
go func() {
|
|
for {
|
|
_, value, ok := reflect.Select(cases)
|
|
if !ok {
|
|
continue
|
|
}
|
|
|
|
request := value.Interface().(OperationRequest)
|
|
|
|
concurrentLimitCond.L.Lock()
|
|
for atomic.LoadInt32(&concurrentUpload) > ConcurrentUploadLimit {
|
|
concurrentLimitCond.Wait()
|
|
}
|
|
atomic.AddInt32(&concurrentUpload, 1)
|
|
concurrentLimitCond.L.Unlock()
|
|
|
|
go func() {
|
|
defer atomic.AddInt32(&concurrentUpload, -1)
|
|
defer concurrentLimitCond.Signal()
|
|
request()
|
|
}()
|
|
|
|
}
|
|
}()
|
|
|
|
}
|
|
|
|
func AsyncOutOfOrderProcess(slotKey uint32, request OperationRequest) {
|
|
index := slotKey % requestSlots
|
|
requests[index] <- request
|
|
}
|