我对大猩猩程序没有结束有问题,尽管有一个WaitGroup.在附加的代码中,您可以看到Heap的置换算法的实现.我想要加快速度,所以我 for each 可能的第一个数字创建了一个Goroutine,从而将每个Goroutine的排列减少到(n-1)!个.总而言之,我应该还有n!个排列(n*(n-1)! = n!个),但我的主 routine 似乎在子 routine 结束之前退出了.然后,我try 跟踪已执行的排列.与我的看法相反,执行的排列的数量并不是恒定的,但总是比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/上,因此它非常可重现)

先谢谢你.

推荐答案

在您的代码中,Goroutines并发访问permutations个变量.当您增加值n时,工作负载会增加,并且会成为导致意外结果的问题.

你可以使用mutex,这将确保一次只有一只猩猩可以访问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)
        }
    }
}

Go相关问答推荐

难以为多个平台添加Go Bazel构建选项

如何使用GO GIN从Auth0 JWT内标识检索权限

Go 1.20 中如何计算连接错误?

Golang 发送Post请求出现400错误

如何在 Go 中将 int 转换为包含 complex128 的泛型类型?

如何将验证器标记添加到嵌套字段

加载 docker 镜像失败

Golang crypto/rand 线程安全吗?

helm :将 YAML 转换为 JSON 时出错:yaml:第 xx 行:未找到预期的密钥

当函数返回一个函数时,为什么 Go 泛型会失败?

来自洪流公告的奇怪同行字段

如何在 helm 中将字符串连接到 .AsConfig 的结果?

如何将多个切片打印为一个切片?

在我的情况下,如何以正确的方式测试方法?

是否可以使用按位运算在随机 unicode 字符串中找到重复字符?

测试包外文件时的 Golang 测试覆盖率

为什么在 goroutine 中声明时,benbjohnson/clock 模拟计时器不执行?

从 map 返回空数组而不是空字符串数组

Beego - 我需要context.Context而不是 Beego 上下文

有没有一种方法可以确保传递的值具有使用泛型的某些字段?