Skip to content

Commit 86341c6

Browse files
committed
Merge pull request #2 from yuya-takeyama/parallel
Add -p (--parallels) option to set parallel degree of execution
2 parents 47f065a + 5db4f46 commit 86341c6

File tree

3 files changed

+69
-14
lines changed

3 files changed

+69
-14
lines changed

README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,12 @@ foo bar baz
1111
foo bar baz
1212
```
1313

14+
### Set parallel degree of execution (-p)
15+
16+
```
17+
$ ntimes 10 -p 3 -- sh -c 'echo "Hi!"; sleep 1; echo "Bye"'
18+
```
19+
1420
## Author
1521

1622
Yuya Takeyama

main.go

Lines changed: 54 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,30 @@
11
package main
22

33
import (
4+
"bytes"
45
"fmt"
56
"io"
67
"os"
78
"os/exec"
89
"strconv"
10+
"sync"
911

1012
flags "github.com/jessevdk/go-flags"
1113
)
1214

1315
const AppName = "ntimes"
1416

15-
type Options struct {
17+
type options struct {
18+
Parallels int `short:"p" long:"parallels" description:"Parallel degree of execution" default:"1"`
1619
ShowVersion bool `short:"v" long:"version" description:"Show version"`
1720
}
1821

19-
var opts Options
22+
var opts options
2023

2124
func main() {
2225
parser := flags.NewParser(&opts, flags.Default^flags.PrintErrors)
2326
parser.Name = AppName
24-
parser.Usage = "[OPTIONS] -- COMMAND"
27+
parser.Usage = "N [OPTIONS] -- COMMAND"
2528

2629
args, err := parser.Parse()
2730

@@ -39,23 +42,61 @@ func main() {
3942
cmdName := args[1]
4043
cmdArgs := args[2:]
4144

45+
stdoutCh := make(chan io.ReadWriter)
46+
exitCh := make(chan bool)
47+
4248
if err != nil {
4349
panic(err)
4450
}
4551

46-
ntimes(cnt, cmdName, cmdArgs, os.Stdin, os.Stdout, os.Stderr)
52+
go printer(os.Stdout, stdoutCh, exitCh)
53+
54+
ntimes(cnt, cmdName, cmdArgs, os.Stdin, os.Stdout, os.Stderr, stdoutCh, opts.Parallels)
55+
56+
exitCh <- true
4757
}
4858

49-
func ntimes(cnt int, cmdName string, cmdArgs []string, stdin io.Reader, stdout io.Writer, stderr io.Writer) {
59+
func ntimes(cnt int, cmdName string, cmdArgs []string, stdin io.Reader, stdout io.Writer, stderr io.Writer, stdoutCh chan io.ReadWriter, parallels int) {
60+
var wg sync.WaitGroup
61+
62+
sema := make(chan bool, parallels)
63+
5064
for i := 0; i < cnt; i++ {
51-
cmd := exec.Command(cmdName, cmdArgs...)
52-
cmd.Stdin = stdin
53-
cmd.Stdout = stdout
54-
cmd.Stderr = stderr
55-
err := cmd.Run()
56-
57-
if err != nil {
58-
panic(err)
65+
wg.Add(1)
66+
go func() {
67+
sema <- true
68+
69+
defer func() {
70+
wg.Done()
71+
<-sema
72+
}()
73+
74+
stdoutBuffer := new(bytes.Buffer)
75+
76+
cmd := exec.Command(cmdName, cmdArgs...)
77+
cmd.Stdin = stdin
78+
cmd.Stdout = stdoutBuffer
79+
cmd.Stderr = stderr
80+
err := cmd.Run()
81+
82+
if err != nil {
83+
panic(err)
84+
}
85+
86+
stdoutCh <- stdoutBuffer
87+
}()
88+
}
89+
90+
wg.Wait()
91+
}
92+
93+
func printer(stdout io.Writer, stdoutCh chan io.ReadWriter, exitCh chan bool) {
94+
for {
95+
select {
96+
case r := <-stdoutCh:
97+
io.Copy(stdout, r)
98+
case <-exitCh:
99+
return
59100
}
60101
}
61102
}

main_test.go

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package main
22

33
import (
44
"bytes"
5+
"io"
56
"testing"
67
)
78

@@ -10,7 +11,14 @@ func TestNtimes(t *testing.T) {
1011
stdout := new(bytes.Buffer)
1112
stderr := new(bytes.Buffer)
1213

13-
ntimes(3, "echo", []string{"foo", "bar", "baz"}, stdin, stdout, stderr)
14+
stdoutCh := make(chan io.ReadWriter)
15+
exitCh := make(chan bool)
16+
17+
go printer(stdout, stdoutCh, exitCh)
18+
19+
ntimes(3, "echo", []string{"foo", "bar", "baz"}, stdin, stdout, stderr, stdoutCh, 1)
20+
21+
exitCh <- true
1422

1523
expected := "foo bar baz\nfoo bar baz\nfoo bar baz\n"
1624
actual := stdout.String()

0 commit comments

Comments
 (0)