mirror of
https://github.com/go-task/task.git
synced 2025-08-10 22:42:19 +02:00
execext: use sync.Pool to instantiate parser and runner
A benchmark was added. The performance improvement is considerable: BenchmarkNoPool-4 30000 43405 ns/op BenchmarkPool-4 20000 71219 ns/op
This commit is contained in:
@@ -5,11 +5,26 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"io"
|
"io"
|
||||||
"strings"
|
"strings"
|
||||||
|
"sync"
|
||||||
|
|
||||||
"mvdan.cc/sh/interp"
|
"mvdan.cc/sh/interp"
|
||||||
"mvdan.cc/sh/syntax"
|
"mvdan.cc/sh/syntax"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
parserPool = sync.Pool{
|
||||||
|
New: func() interface{} {
|
||||||
|
return syntax.NewParser()
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
runnerPool = sync.Pool{
|
||||||
|
New: func() interface{} {
|
||||||
|
return &interp.Runner{}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
// RunCommandOptions is the options for the RunCommand func
|
// RunCommandOptions is the options for the RunCommand func
|
||||||
type RunCommandOptions struct {
|
type RunCommandOptions struct {
|
||||||
Context context.Context
|
Context context.Context
|
||||||
@@ -32,19 +47,24 @@ func RunCommand(opts *RunCommandOptions) error {
|
|||||||
return ErrNilOptions
|
return ErrNilOptions
|
||||||
}
|
}
|
||||||
|
|
||||||
p, err := syntax.NewParser().Parse(strings.NewReader(opts.Command), "")
|
parser := parserPool.Get().(*syntax.Parser)
|
||||||
|
defer parserPool.Put(parser)
|
||||||
|
|
||||||
|
p, err := parser.Parse(strings.NewReader(opts.Command), "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
r := interp.Runner{
|
r := runnerPool.Get().(*interp.Runner)
|
||||||
Context: opts.Context,
|
defer runnerPool.Put(r)
|
||||||
Dir: opts.Dir,
|
|
||||||
Env: opts.Env,
|
r.Context = opts.Context
|
||||||
Stdin: opts.Stdin,
|
r.Dir = opts.Dir
|
||||||
Stdout: opts.Stdout,
|
r.Env = opts.Env
|
||||||
Stderr: opts.Stderr,
|
r.Stdin = opts.Stdin
|
||||||
}
|
r.Stdout = opts.Stdout
|
||||||
|
r.Stderr = opts.Stderr
|
||||||
|
|
||||||
if err = r.Reset(); err != nil {
|
if err = r.Reset(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
69
execext/exec_test.go
Normal file
69
execext/exec_test.go
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
// execext_test.go
|
||||||
|
package execext
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"io/ioutil"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"mvdan.cc/sh/interp"
|
||||||
|
"mvdan.cc/sh/syntax"
|
||||||
|
)
|
||||||
|
|
||||||
|
func BenchmarkNoPool(b *testing.B) {
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
f, err := syntax.NewParser().Parse(strings.NewReader(`echo "Hello, World!"`), "")
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
r := interp.Runner{
|
||||||
|
Context: context.TODO(),
|
||||||
|
Stdout: ioutil.Discard,
|
||||||
|
Stderr: ioutil.Discard,
|
||||||
|
}
|
||||||
|
if err = r.Reset(); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
if err = r.Run(f); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkPool(b *testing.B) {
|
||||||
|
parserPool := sync.Pool{
|
||||||
|
New: func() interface{} {
|
||||||
|
return syntax.NewParser()
|
||||||
|
},
|
||||||
|
}
|
||||||
|
runnerPool := sync.Pool{
|
||||||
|
New: func() interface{} {
|
||||||
|
return &interp.Runner{}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
parser := parserPool.Get().(*syntax.Parser)
|
||||||
|
defer parserPool.Put(parser)
|
||||||
|
|
||||||
|
f, err := parser.Parse(strings.NewReader(`echo "Hello, World!"`), "")
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
r := runnerPool.Get().(*interp.Runner)
|
||||||
|
defer runnerPool.Put(r)
|
||||||
|
|
||||||
|
r.Stdout = ioutil.Discard
|
||||||
|
r.Stderr = ioutil.Discard
|
||||||
|
|
||||||
|
if err = r.Reset(); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
if err = r.Run(f); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user