concurrency implemented
This commit is contained in:
parent
16a24dc92b
commit
1fa57347aa
2
.gitignore
vendored
2
.gitignore
vendored
@ -0,0 +1,2 @@
|
|||||||
|
/*.txt
|
||||||
|
/*.pprof
|
@ -2,7 +2,6 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"log"
|
"log"
|
||||||
"runtime"
|
|
||||||
|
|
||||||
"github.com/golangci/golangci-lint/internal/commands"
|
"github.com/golangci/golangci-lint/internal/commands"
|
||||||
"github.com/golangci/golangci-shared/pkg/analytics"
|
"github.com/golangci/golangci-shared/pkg/analytics"
|
||||||
@ -12,7 +11,6 @@ import (
|
|||||||
func main() {
|
func main() {
|
||||||
log.SetFlags(0) // don't print time
|
log.SetFlags(0) // don't print time
|
||||||
analytics.SetLogLevel(logrus.WarnLevel)
|
analytics.SetLogLevel(logrus.WarnLevel)
|
||||||
runtime.GOMAXPROCS(runtime.NumCPU())
|
|
||||||
|
|
||||||
e := commands.NewExecutor()
|
e := commands.NewExecutor()
|
||||||
if err := e.Execute(); err != nil {
|
if err := e.Execute(); err != nil {
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
package commands
|
package commands
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"runtime"
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -15,5 +17,6 @@ func (e *Executor) initRoot() {
|
|||||||
}
|
}
|
||||||
rootCmd.PersistentFlags().BoolVarP(&e.cfg.Common.IsVerbose, "verbose", "v", false, "verbose output")
|
rootCmd.PersistentFlags().BoolVarP(&e.cfg.Common.IsVerbose, "verbose", "v", false, "verbose output")
|
||||||
rootCmd.PersistentFlags().StringVar(&e.cfg.Common.CPUProfilePath, "cpu-profile-path", "", "Path to CPU profile output file")
|
rootCmd.PersistentFlags().StringVar(&e.cfg.Common.CPUProfilePath, "cpu-profile-path", "", "Path to CPU profile output file")
|
||||||
|
rootCmd.PersistentFlags().IntVarP(&e.cfg.Common.Concurrency, "concurrency", "j", runtime.NumCPU(), "Concurrency")
|
||||||
e.rootCmd = rootCmd
|
e.rootCmd = rootCmd
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
|
"runtime"
|
||||||
"runtime/pprof"
|
"runtime/pprof"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
@ -48,6 +49,8 @@ func (e *Executor) initRun() {
|
|||||||
|
|
||||||
func (e Executor) executeRun(cmd *cobra.Command, args []string) {
|
func (e Executor) executeRun(cmd *cobra.Command, args []string) {
|
||||||
f := func() (error, int) {
|
f := func() (error, int) {
|
||||||
|
runtime.GOMAXPROCS(e.cfg.Common.Concurrency)
|
||||||
|
|
||||||
if e.cfg.Common.CPUProfilePath != "" {
|
if e.cfg.Common.CPUProfilePath != "" {
|
||||||
f, err := os.Create(e.cfg.Common.CPUProfilePath)
|
f, err := os.Create(e.cfg.Common.CPUProfilePath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -82,7 +85,7 @@ func (e Executor) executeRun(cmd *cobra.Command, args []string) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
issues, err := runner.Run(ctx, golinters.GetSupportedLinters(), exec, &e.cfg.Run)
|
issues, err := runner.Run(ctx, golinters.GetSupportedLinters(), exec, e.cfg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err, 1
|
return err, 1
|
||||||
}
|
}
|
||||||
@ -112,7 +115,7 @@ func outputIssues(format string, issues []result.Issue) error {
|
|||||||
if format == config.OutFormatColoredLineNumber {
|
if format == config.OutFormatColoredLineNumber {
|
||||||
outStr = color.GreenString(outStr)
|
outStr = color.GreenString(outStr)
|
||||||
}
|
}
|
||||||
log.Print(outStr)
|
fmt.Fprint(os.Stdout, outStr)
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, i := range issues {
|
for _, i := range issues {
|
||||||
@ -120,7 +123,7 @@ func outputIssues(format string, issues []result.Issue) error {
|
|||||||
if format == config.OutFormatColoredLineNumber {
|
if format == config.OutFormatColoredLineNumber {
|
||||||
text = color.RedString(text)
|
text = color.RedString(text)
|
||||||
}
|
}
|
||||||
log.Printf("%s:%d: %s", i.File, i.LineNumber, text)
|
fmt.Fprintf(os.Stdout, "%s:%d: %s\n", i.File, i.LineNumber, text)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -130,7 +133,7 @@ func outputIssues(format string, issues []result.Issue) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
log.Print(string(outputJSON))
|
fmt.Fprint(os.Stdout, string(outputJSON))
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -15,6 +15,7 @@ var OutFormats = []string{OutFormatColoredLineNumber, OutFormatLineNumber, OutFo
|
|||||||
type Common struct {
|
type Common struct {
|
||||||
IsVerbose bool
|
IsVerbose bool
|
||||||
CPUProfilePath string
|
CPUProfilePath string
|
||||||
|
Concurrency int
|
||||||
}
|
}
|
||||||
|
|
||||||
type Run struct {
|
type Run struct {
|
||||||
|
@ -4,6 +4,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
"sync"
|
||||||
|
|
||||||
"github.com/golangci/golangci-lint/pkg/config"
|
"github.com/golangci/golangci-lint/pkg/config"
|
||||||
"github.com/golangci/golangci-lint/pkg/result"
|
"github.com/golangci/golangci-lint/pkg/result"
|
||||||
@ -13,35 +14,87 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type Runner interface {
|
type Runner interface {
|
||||||
Run(ctx context.Context, linters []Linter, exec executors.Executor, cfg *config.Run) ([]result.Issue, error)
|
Run(ctx context.Context, linters []Linter, exec executors.Executor, cfg *config.Config) ([]result.Issue, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
type SimpleRunner struct {
|
type SimpleRunner struct {
|
||||||
Processors []processors.Processor
|
Processors []processors.Processor
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r SimpleRunner) Run(ctx context.Context, linters []Linter, exec executors.Executor, cfg *config.Run) ([]result.Issue, error) {
|
type lintRes struct {
|
||||||
results := []result.Result{}
|
linter Linter
|
||||||
|
err error
|
||||||
|
res *result.Result
|
||||||
|
}
|
||||||
|
|
||||||
|
func runLinters(ctx context.Context, wg *sync.WaitGroup, tasksCh chan Linter, lintResultsCh chan lintRes, exec executors.Executor, cfg *config.Config) {
|
||||||
|
for i := 0; i < cfg.Common.Concurrency; i++ {
|
||||||
|
go func() {
|
||||||
|
defer wg.Done()
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
// XXX: if check it in a select with reading from tasksCh
|
||||||
|
// it's possible to not enter to this case until tasksCh is empty.
|
||||||
|
return
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
return
|
||||||
|
case linter, ok := <-tasksCh:
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
res, lerr := linter.Run(ctx, exec, &cfg.Run)
|
||||||
|
lintResultsCh <- lintRes{
|
||||||
|
linter: linter,
|
||||||
|
err: lerr,
|
||||||
|
res: res,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r SimpleRunner) Run(ctx context.Context, linters []Linter, exec executors.Executor, cfg *config.Config) ([]result.Issue, error) {
|
||||||
savedStdout, savedStderr := os.Stdout, os.Stderr
|
savedStdout, savedStderr := os.Stdout, os.Stderr
|
||||||
devNull, err := os.Open(os.DevNull)
|
devNull, err := os.Open(os.DevNull)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("can't open null device %q: %s", os.DevNull, err)
|
return nil, fmt.Errorf("can't open null device %q: %s", os.DevNull, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
os.Stdout, os.Stderr = devNull, devNull
|
||||||
|
|
||||||
|
lintResultsCh := make(chan lintRes, len(linters))
|
||||||
|
tasksCh := make(chan Linter, cfg.Common.Concurrency)
|
||||||
|
var wg sync.WaitGroup
|
||||||
|
wg.Add(cfg.Common.Concurrency)
|
||||||
|
runLinters(ctx, &wg, tasksCh, lintResultsCh, exec, cfg)
|
||||||
|
|
||||||
for _, linter := range linters {
|
for _, linter := range linters {
|
||||||
os.Stdout, os.Stderr = devNull, devNull
|
tasksCh <- linter
|
||||||
res, err := linter.Run(ctx, exec, cfg)
|
}
|
||||||
os.Stdout, os.Stderr = savedStdout, savedStderr
|
|
||||||
if err != nil {
|
close(tasksCh)
|
||||||
analytics.Log(ctx).Warnf("Can't run linter %s: %s", linter.Name(), err)
|
wg.Wait()
|
||||||
|
close(lintResultsCh)
|
||||||
|
|
||||||
|
os.Stdout, os.Stderr = savedStdout, savedStderr
|
||||||
|
results := []result.Result{}
|
||||||
|
for res := range lintResultsCh {
|
||||||
|
if res.err != nil {
|
||||||
|
analytics.Log(ctx).Warnf("Can't run linter %s: %s", res.linter.Name(), res.err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(res.Issues) == 0 {
|
if res.res == nil || len(res.res.Issues) == 0 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
results = append(results, *res)
|
results = append(results, *res.res)
|
||||||
}
|
}
|
||||||
|
|
||||||
results, err = r.processResults(results)
|
results, err = r.processResults(results)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user