英文:
Goroutines seem to be interrupted despite the presence of a WaitGroup
问题
我有一个问题,尽管使用了WaitGroup,但goroutine没有结束。在附加的代码中,您可以看到对排列的Heap算法的实现。我想加快速度,所以我为每个可能的第一个数字创建了一个goroutine,从而将每个goroutine的排列减少到(n-1)!
。总共,我应该仍然有n!
个排列(n*(n-1)! = n!
),但是我的主程序似乎在子程序完成之前退出了。然后,我尝试跟踪执行的排列。与我的信念相反,执行的排列数量并不是恒定的,而是总是略微(对于较小的n
)或非常(对于较大的n
)小于n!
。
例如,n=4
的排列每次都是24,即4!
,因此所有的goroutine都已经完成。如果我有一个更大的数字,比如n=8
,我得到的值大约是13500
,而不是预期的40000 = 8!
。
这种行为是从哪里来的?如何确保在主程序退出之前,所有的goroutine都已经完成?
package main
import (
"fmt"
"sync"
)
var wg sync.WaitGroup
var permutations int
func main() {
n := 9
wg.Add(n)
for i := 0; i < n; i++ {
var arr []int
for j := 0; j < n; j++ {
if i != j {
arr = append(arr, j+1)
}
}
go threadFunction(n-1, i+1, arr)
}
wg.Wait()
fmt.Println(permutations)
}
func threadFunction(k int, suffix int, arr []int) {
defer wg.Done()
heapPermutation(k, suffix, arr)
}
func heapPermutation(k int, prefix int, arr []int) {
if k == 1 {
arr = append(arr, prefix)
// fmt.Println(arr)
permutations++
} else {
heapPermutation(k-1, prefix, arr)
for i := 0; i < k-1; i++ {
if k%2 == 0 {
arr[i], arr[k-1] = arr[k-1], arr[i]
} else {
arr[0], arr[k-1] = arr[k-1], arr[0]
}
heapPermutation(k-1, prefix, arr)
}
}
}
(在https://go.dev/play/上也可以很容易地实现相同的行为,因此它是可以重现的。)
英文:
I have a problem with goroutines not concluding in spite of a WaitGroup. In the code appended, you can see an implementation of Heap's algorithm for permutations. I wanted to speed it up, and so I created a goroutine for every possible first number and thereby decreased the permutations per goroutine to (n-1)!
. In total, I should still have n!
permutations (n*(n-1)! = n!
), but my main routine seems to exit before the sub routines are finished. I then tried tracking the executed permutations. Against my belief, the number of permutations executed isn't constant, but always a bit (for low n
) or very much (for large n
) under n!
.
For example, the permutations for n=4
is 24 every time, that is 4!
and thereby all goroutines have finished. If I have a higher number like n=8
, I get a value around 13500
and not the expected 40000 = 8!
.
Where does this behavior come from? How can I ensure that all my goroutines have finished before the main program exits?
package main
import (
"fmt"
"sync"
)
var wg sync.WaitGroup
var permutations int
func main() {
n := 9
wg.Add(n)
for i := 0; i < n; i++ {
var arr []int
for j := 0; j < n; j++ {
if i != j {
arr = append(arr, j+1)
}
}
go threadFunction(n-1, i+1, arr)
}
wg.Wait()
fmt.Println(permutations)
}
func threadFunction(k int, suffix int, arr []int) {
defer wg.Done()
heapPermutation(k, suffix, arr)
}
func heapPermutation(k int, prefix int, arr []int) {
if k == 1 {
arr = append(arr, prefix)
// fmt.Println(arr)
permutations++
} else {
heapPermutation(k-1, prefix, arr)
for i := 0; i < k-1; i++ {
if k%2 == 0 {
arr[i], arr[k-1] = arr[k-1], arr[i]
} else {
arr[0], arr[k-1] = arr[k-1], arr[0]
}
heapPermutation(k-1, prefix, arr)
}
}
}
(The same behavior can be easily achieved, e.g. on https://go.dev/play/, thus it is very much reproducible.)
答案1
得分: 2
在你的代码中,goroutine 并发访问了 permutations
变量。当你增加 n
的值时,工作负载增加,这导致了意外结果的问题。
你可以使用一个 mutex
,它可以确保只有一个 goroutine 可以同时访问 permutations
。
package main
import (
"fmt"
"sync"
)
var wg sync.WaitGroup
var permutations int
var permutationsMutex sync.Mutex
func main() {
n := 9
wg.Add(n)
for i := 0; i < n; i++ {
var arr []int
for j := 0; j < n; j++ {
if i != j {
arr = append(arr, j+1)
}
}
go threadFunction(n-1, i+1, arr)
}
wg.Wait()
fmt.Println(permutations)
}
func threadFunction(k int, suffix int, arr []int) {
defer wg.Done()
heapPermutation(k, suffix, arr)
}
func heapPermutation(k int, prefix int, arr []int) {
if k == 1 {
arr = append(arr, prefix)
permutationsMutex.Lock()
permutations++
permutationsMutex.Unlock()
} else {
heapPermutation(k-1, prefix, arr)
for i := 0; i < k-1; i++ {
if k%2 == 0 {
arr[i], arr[k-1] = arr[k-1], arr[i]
} else {
arr[0], arr[k-1] = arr[k-1], arr[0]
}
heapPermutation(k-1, prefix, arr)
}
}
}
希望对你有帮助!
英文:
In your code, goroutines access permutations
variable concurrently. When you increase value of n
, the workload increases and it becomes the issue leading to an unexpected result.
You can use a mutex
, it will ensure that only one goroutine can access the permutations
at the time.
package main
import (
"fmt"
"sync"
)
var wg sync.WaitGroup
var permutations int
var permutationsMutex sync.Mutex
func main() {
n := 9
wg.Add(n)
for i := 0; i < n; i++ {
var arr []int
for j := 0; j < n; j++ {
if i != j {
arr = append(arr, j+1)
}
}
go threadFunction(n-1, i+1, arr)
}
wg.Wait()
fmt.Println(permutations)
}
func threadFunction(k int, suffix int, arr []int) {
defer wg.Done()
heapPermutation(k, suffix, arr)
}
func heapPermutation(k int, prefix int, arr []int) {
if k == 1 {
arr = append(arr, prefix)
permutationsMutex.Lock()
permutations++
permutationsMutex.Unlock()
} else {
heapPermutation(k-1, prefix, arr)
for i := 0; i < k-1; i++ {
if k%2 == 0 {
arr[i], arr[k-1] = arr[k-1], arr[i]
} else {
arr[0], arr[k-1] = arr[k-1], arr[0]
}
heapPermutation(k-1, prefix, arr)
}
}
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论