func.go 1.6 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879
  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 interface{})) func(ctx interface{}) bool {
  20. if f == nil {
  21. panic("BUG: f cannot be nil")
  22. }
  23. funcWorkCh := make(chan *funcWork, runtime.GOMAXPROCS(-1)*2048)
  24. onceInit := func() {
  25. n := runtime.GOMAXPROCS(-1)
  26. for i := 0; i < n; i++ {
  27. go funcWorker(funcWorkCh, f)
  28. }
  29. }
  30. var once sync.Once
  31. return func(ctx interface{}) bool {
  32. once.Do(onceInit)
  33. fw := getFuncWork()
  34. fw.ctx = ctx
  35. select {
  36. case funcWorkCh <- fw:
  37. default:
  38. putFuncWork(fw)
  39. return false
  40. }
  41. <-fw.done
  42. putFuncWork(fw)
  43. return true
  44. }
  45. }
  46. func funcWorker(funcWorkCh <-chan *funcWork, f func(ctx interface{})) {
  47. for fw := range funcWorkCh {
  48. f(fw.ctx)
  49. fw.done <- struct{}{}
  50. }
  51. }
  52. func getFuncWork() *funcWork {
  53. v := funcWorkPool.Get()
  54. if v == nil {
  55. v = &funcWork{
  56. done: make(chan struct{}, 1),
  57. }
  58. }
  59. return v.(*funcWork)
  60. }
  61. func putFuncWork(fw *funcWork) {
  62. fw.ctx = nil
  63. funcWorkPool.Put(fw)
  64. }
  65. var funcWorkPool sync.Pool
  66. type funcWork struct {
  67. ctx interface{}
  68. done chan struct{}
  69. }