func.go 1.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980
  1. package stackless
  2. import (
  3. "runtime"
  4. "sync"
  5. )
  6. // NewFunc returns stackless wrapper for the function f.
  7. //
  8. // Unlike f, the returned stackless wrapper doesn't use stack space
  9. // on the goroutine that calls it.
  10. // The wrapper may save a lot of stack space if the following conditions
  11. // are met:
  12. //
  13. // - f doesn't contain blocking calls on network, I/O or channels;
  14. // - f uses a lot of stack space;
  15. // - the wrapper is called from high number of concurrent goroutines.
  16. //
  17. // The stackless wrapper returns false if the call cannot be processed
  18. // at the moment due to high load.
  19. func NewFunc(f func(ctx any)) func(ctx any) bool {
  20. if f == nil {
  21. // developer sanity-check
  22. panic("BUG: f cannot be nil")
  23. }
  24. funcWorkCh := make(chan *funcWork, runtime.GOMAXPROCS(-1)*2048)
  25. onceInit := func() {
  26. n := runtime.GOMAXPROCS(-1)
  27. for i := 0; i < n; i++ {
  28. go funcWorker(funcWorkCh, f)
  29. }
  30. }
  31. var once sync.Once
  32. return func(ctx any) bool {
  33. once.Do(onceInit)
  34. fw := getFuncWork()
  35. fw.ctx = ctx
  36. select {
  37. case funcWorkCh <- fw:
  38. default:
  39. putFuncWork(fw)
  40. return false
  41. }
  42. <-fw.done
  43. putFuncWork(fw)
  44. return true
  45. }
  46. }
  47. func funcWorker(funcWorkCh <-chan *funcWork, f func(ctx any)) {
  48. for fw := range funcWorkCh {
  49. f(fw.ctx)
  50. fw.done <- struct{}{}
  51. }
  52. }
  53. func getFuncWork() *funcWork {
  54. v := funcWorkPool.Get()
  55. if v == nil {
  56. v = &funcWork{
  57. done: make(chan struct{}, 1),
  58. }
  59. }
  60. return v.(*funcWork)
  61. }
  62. func putFuncWork(fw *funcWork) {
  63. fw.ctx = nil
  64. funcWorkPool.Put(fw)
  65. }
  66. var funcWorkPool sync.Pool
  67. type funcWork struct {
  68. ctx any
  69. done chan struct{}
  70. }