1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980 |
- package stackless
- import (
- "runtime"
- "sync"
- )
- // NewFunc returns stackless wrapper for the function f.
- //
- // Unlike f, the returned stackless wrapper doesn't use stack space
- // on the goroutine that calls it.
- // The wrapper may save a lot of stack space if the following conditions
- // are met:
- //
- // - f doesn't contain blocking calls on network, I/O or channels;
- // - f uses a lot of stack space;
- // - the wrapper is called from high number of concurrent goroutines.
- //
- // The stackless wrapper returns false if the call cannot be processed
- // at the moment due to high load.
- func NewFunc(f func(ctx any)) func(ctx any) bool {
- if f == nil {
- // developer sanity-check
- panic("BUG: f cannot be nil")
- }
- funcWorkCh := make(chan *funcWork, runtime.GOMAXPROCS(-1)*2048)
- onceInit := func() {
- n := runtime.GOMAXPROCS(-1)
- for i := 0; i < n; i++ {
- go funcWorker(funcWorkCh, f)
- }
- }
- var once sync.Once
- return func(ctx any) bool {
- once.Do(onceInit)
- fw := getFuncWork()
- fw.ctx = ctx
- select {
- case funcWorkCh <- fw:
- default:
- putFuncWork(fw)
- return false
- }
- <-fw.done
- putFuncWork(fw)
- return true
- }
- }
- func funcWorker(funcWorkCh <-chan *funcWork, f func(ctx any)) {
- for fw := range funcWorkCh {
- f(fw.ctx)
- fw.done <- struct{}{}
- }
- }
- func getFuncWork() *funcWork {
- v := funcWorkPool.Get()
- if v == nil {
- v = &funcWork{
- done: make(chan struct{}, 1),
- }
- }
- return v.(*funcWork)
- }
- func putFuncWork(fw *funcWork) {
- fw.ctx = nil
- funcWorkPool.Put(fw)
- }
- var funcWorkPool sync.Pool
- type funcWork struct {
- ctx any
- done chan struct{}
- }
|