Skip to content

Commit f30044a

Browse files
committed
cmd/go/internal: remove some users of par.Work
par.Work is used in a number of places as a parallel work queue. This change replaces it with goroutines and channels in a number of simpler places where it's used. Change-Id: I0620eda46ec7b2c0599a8b9361639af7bb73a05a Reviewed-on: https://go-review.googlesource.com/c/go/+/248326 Run-TryBot: Michael Matloob <[email protected]> TryBot-Result: Gobot Gobot <[email protected]> Reviewed-by: Bryan C. Mills <[email protected]>
1 parent 2ac4bf3 commit f30044a

File tree

5 files changed

+133
-92
lines changed

5 files changed

+133
-92
lines changed

src/cmd/go/internal/modcmd/download.go

Lines changed: 39 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,15 @@
55
package modcmd
66

77
import (
8+
"cmd/go/internal/modfetch"
89
"context"
910
"encoding/json"
1011
"os"
12+
"runtime"
1113

1214
"cmd/go/internal/base"
1315
"cmd/go/internal/cfg"
14-
"cmd/go/internal/modfetch"
1516
"cmd/go/internal/modload"
16-
"cmd/go/internal/par"
1717
"cmd/go/internal/work"
1818

1919
"golang.org/x/mod/module"
@@ -102,33 +102,7 @@ func runDownload(ctx context.Context, cmd *base.Command, args []string) {
102102
}
103103
}
104104

105-
var mods []*moduleJSON
106-
var work par.Work
107-
listU := false
108-
listVersions := false
109-
for _, info := range modload.ListModules(ctx, args, listU, listVersions) {
110-
if info.Replace != nil {
111-
info = info.Replace
112-
}
113-
if info.Version == "" && info.Error == nil {
114-
// main module or module replaced with file path.
115-
// Nothing to download.
116-
continue
117-
}
118-
m := &moduleJSON{
119-
Path: info.Path,
120-
Version: info.Version,
121-
}
122-
mods = append(mods, m)
123-
if info.Error != nil {
124-
m.Error = info.Error.Err
125-
continue
126-
}
127-
work.Add(m)
128-
}
129-
130-
work.Do(10, func(item interface{}) {
131-
m := item.(*moduleJSON)
105+
downloadModule := func(m *moduleJSON) {
132106
var err error
133107
m.Info, err = modfetch.InfoFile(m.Path, m.Version)
134108
if err != nil {
@@ -157,7 +131,42 @@ func runDownload(ctx context.Context, cmd *base.Command, args []string) {
157131
m.Error = err.Error()
158132
return
159133
}
160-
})
134+
}
135+
136+
var mods []*moduleJSON
137+
listU := false
138+
listVersions := false
139+
type token struct{}
140+
sem := make(chan token, runtime.GOMAXPROCS(0))
141+
for _, info := range modload.ListModules(ctx, args, listU, listVersions) {
142+
if info.Replace != nil {
143+
info = info.Replace
144+
}
145+
if info.Version == "" && info.Error == nil {
146+
// main module or module replaced with file path.
147+
// Nothing to download.
148+
continue
149+
}
150+
m := &moduleJSON{
151+
Path: info.Path,
152+
Version: info.Version,
153+
}
154+
mods = append(mods, m)
155+
if info.Error != nil {
156+
m.Error = info.Error.Err
157+
continue
158+
}
159+
sem <- token{}
160+
go func() {
161+
downloadModule(m)
162+
<-sem
163+
}()
164+
}
165+
166+
// Fill semaphore channel to wait for goroutines to finish.
167+
for n := cap(sem); n > 0; n-- {
168+
sem <- token{}
169+
}
161170

162171
if *downloadJSON {
163172
for _, m := range mods {

src/cmd/go/internal/modcmd/graph.go

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ import (
1515
"cmd/go/internal/base"
1616
"cmd/go/internal/cfg"
1717
"cmd/go/internal/modload"
18-
"cmd/go/internal/par"
1918
"cmd/go/internal/work"
2019

2120
"golang.org/x/mod/module"
@@ -59,23 +58,25 @@ func runGraph(ctx context.Context, cmd *base.Command, args []string) {
5958
return m.Path + "@" + m.Version
6059
}
6160

62-
// Note: using par.Work only to manage work queue.
63-
// No parallelism here, so no locking.
6461
var out []string
6562
var deps int // index in out where deps start
66-
var work par.Work
67-
work.Add(modload.Target)
68-
work.Do(1, func(item interface{}) {
69-
m := item.(module.Version)
63+
seen := map[module.Version]bool{modload.Target: true}
64+
queue := []module.Version{modload.Target}
65+
for len(queue) > 0 {
66+
var m module.Version
67+
m, queue = queue[0], queue[1:]
7068
list, _ := reqs.Required(m)
7169
for _, r := range list {
72-
work.Add(r)
70+
if !seen[r] {
71+
queue = append(queue, r)
72+
seen[r] = true
73+
}
7374
out = append(out, format(m)+" "+format(r)+"\n")
7475
}
7576
if m == modload.Target {
7677
deps = len(out)
7778
}
78-
})
79+
}
7980

8081
sort.Slice(out[deps:], func(i, j int) bool {
8182
return out[deps+i][0] < out[deps+j][0]

src/cmd/go/internal/modconv/convert.go

Lines changed: 32 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,12 @@ package modconv
77
import (
88
"fmt"
99
"os"
10+
"runtime"
1011
"sort"
1112
"strings"
12-
"sync"
1313

1414
"cmd/go/internal/base"
1515
"cmd/go/internal/modfetch"
16-
"cmd/go/internal/par"
1716

1817
"golang.org/x/mod/modfile"
1918
"golang.org/x/mod/module"
@@ -42,46 +41,52 @@ func ConvertLegacyConfig(f *modfile.File, file string, data []byte) error {
4241

4342
// Convert requirements block, which may use raw SHA1 hashes as versions,
4443
// to valid semver requirement list, respecting major versions.
45-
var (
46-
work par.Work
47-
mu sync.Mutex
48-
need = make(map[string]string)
49-
replace = make(map[string]*modfile.Replace)
50-
)
44+
versions := make([]*module.Version, len(mf.Require))
45+
replace := make(map[string]*modfile.Replace)
5146

5247
for _, r := range mf.Replace {
5348
replace[r.New.Path] = r
5449
replace[r.Old.Path] = r
5550
}
56-
for _, r := range mf.Require {
51+
52+
type token struct{}
53+
sem := make(chan token, runtime.GOMAXPROCS(0))
54+
for i, r := range mf.Require {
5755
m := r.Mod
5856
if m.Path == "" {
5957
continue
6058
}
6159
if re, ok := replace[m.Path]; ok {
62-
work.Add(re.New)
63-
continue
60+
m = re.New
6461
}
65-
work.Add(r.Mod)
62+
sem <- token{}
63+
go func(i int, m module.Version) {
64+
repo, info, err := modfetch.ImportRepoRev(m.Path, m.Version)
65+
if err != nil {
66+
fmt.Fprintf(os.Stderr, "go: converting %s: stat %s@%s: %v\n", base.ShortPath(file), m.Path, m.Version, err)
67+
return
68+
}
69+
70+
path := repo.ModulePath()
71+
versions[i].Path = path
72+
versions[i].Version = info.Version
73+
74+
<-sem
75+
}(i, m)
76+
}
77+
// Fill semaphore channel to wait for all tasks to finish.
78+
for n := cap(sem); n > 0; n-- {
79+
sem <- token{}
6680
}
6781

68-
work.Do(10, func(item interface{}) {
69-
r := item.(module.Version)
70-
repo, info, err := modfetch.ImportRepoRev(r.Path, r.Version)
71-
if err != nil {
72-
fmt.Fprintf(os.Stderr, "go: converting %s: stat %s@%s: %v\n", base.ShortPath(file), r.Path, r.Version, err)
73-
return
74-
}
75-
mu.Lock()
76-
path := repo.ModulePath()
82+
need := map[string]string{}
83+
for _, v := range versions {
7784
// Don't use semver.Max here; need to preserve +incompatible suffix.
78-
if v, ok := need[path]; !ok || semver.Compare(v, info.Version) < 0 {
79-
need[path] = info.Version
85+
if needv, ok := need[v.Path]; !ok || semver.Compare(needv, v.Version) < 0 {
86+
need[v.Path] = v.Version
8087
}
81-
mu.Unlock()
82-
})
83-
84-
var paths []string
88+
}
89+
paths := make([]string, 0, len(need))
8590
for path := range need {
8691
paths = append(paths, path)
8792
}

src/cmd/go/internal/modget/get.go

Lines changed: 28 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
"fmt"
1212
"os"
1313
"path/filepath"
14+
"runtime"
1415
"sort"
1516
"strings"
1617
"sync"
@@ -21,7 +22,6 @@ import (
2122
"cmd/go/internal/load"
2223
"cmd/go/internal/modload"
2324
"cmd/go/internal/mvs"
24-
"cmd/go/internal/par"
2525
"cmd/go/internal/search"
2626
"cmd/go/internal/work"
2727

@@ -725,18 +725,8 @@ func runGet(ctx context.Context, cmd *base.Command, args []string) {
725725
// reported. A map from module paths to queries is returned, which includes
726726
// queries and modOnly.
727727
func runQueries(ctx context.Context, cache map[querySpec]*query, queries []*query, modOnly map[string]*query) map[string]*query {
728-
var lookup par.Work
729-
for _, q := range queries {
730-
if cached := cache[q.querySpec]; cached != nil {
731-
*q = *cached
732-
} else {
733-
cache[q.querySpec] = q
734-
lookup.Add(q)
735-
}
736-
}
737728

738-
lookup.Do(10, func(item interface{}) {
739-
q := item.(*query)
729+
runQuery := func(q *query) {
740730
if q.vers == "none" {
741731
// Wait for downgrade step.
742732
q.m = module.Version{Path: q.path, Version: "none"}
@@ -747,7 +737,32 @@ func runQueries(ctx context.Context, cache map[querySpec]*query, queries []*quer
747737
base.Errorf("go get %s: %v", q.arg, err)
748738
}
749739
q.m = m
750-
})
740+
}
741+
742+
type token struct{}
743+
sem := make(chan token, runtime.GOMAXPROCS(0))
744+
for _, q := range queries {
745+
if cached := cache[q.querySpec]; cached != nil {
746+
*q = *cached
747+
} else {
748+
sem <- token{}
749+
go func(q *query) {
750+
runQuery(q)
751+
<-sem
752+
}(q)
753+
}
754+
}
755+
756+
// Fill semaphore channel to wait for goroutines to finish.
757+
for n := cap(sem); n > 0; n-- {
758+
sem <- token{}
759+
}
760+
761+
// Add to cache after concurrent section to avoid races...
762+
for _, q := range queries {
763+
cache[q.querySpec] = q
764+
}
765+
751766
base.ExitIfErrors()
752767

753768
byPath := make(map[string]*query)

src/cmd/go/internal/modload/list.go

Lines changed: 24 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -9,37 +9,48 @@ import (
99
"errors"
1010
"fmt"
1111
"os"
12+
"runtime"
1213
"strings"
1314

1415
"cmd/go/internal/base"
1516
"cmd/go/internal/cfg"
1617
"cmd/go/internal/modinfo"
17-
"cmd/go/internal/par"
1818
"cmd/go/internal/search"
1919

2020
"golang.org/x/mod/module"
2121
)
2222

2323
func ListModules(ctx context.Context, args []string, listU, listVersions bool) []*modinfo.ModulePublic {
2424
mods := listModules(ctx, args, listVersions)
25+
26+
type token struct{}
27+
sem := make(chan token, runtime.GOMAXPROCS(0))
2528
if listU || listVersions {
26-
var work par.Work
2729
for _, m := range mods {
28-
work.Add(m)
30+
add := func(m *modinfo.ModulePublic) {
31+
sem <- token{}
32+
go func() {
33+
if listU {
34+
addUpdate(m)
35+
}
36+
if listVersions {
37+
addVersions(m)
38+
}
39+
<-sem
40+
}()
41+
}
42+
43+
add(m)
2944
if m.Replace != nil {
30-
work.Add(m.Replace)
45+
add(m.Replace)
3146
}
3247
}
33-
work.Do(10, func(item interface{}) {
34-
m := item.(*modinfo.ModulePublic)
35-
if listU {
36-
addUpdate(m)
37-
}
38-
if listVersions {
39-
addVersions(m)
40-
}
41-
})
4248
}
49+
// Fill semaphore channel to wait for all tasks to finish.
50+
for n := cap(sem); n > 0; n-- {
51+
sem <- token{}
52+
}
53+
4354
return mods
4455
}
4556

0 commit comments

Comments
 (0)