首頁 >後端開發 >Golang >儘管有 WaitGroup,Goroutines 似乎還是被中斷了

儘管有 WaitGroup,Goroutines 似乎還是被中斷了

PHPz
PHPz轉載
2024-02-06 09:06:07974瀏覽

尽管存在 WaitGroup,Goroutines 似乎还是被中断了

問題內容

儘管存在 waitgroup,但我遇到了 goroutine 未結束的問題。在附加的程式碼中,您可以看到堆排列演算法的實作。我想加快速度,因此我為每個可能的第一個數字創建了一個 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/ 上,因此它的重現性非常好。)


正確答案


############## #####在您的程式碼中,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)
        }
    }
}

以上是儘管有 WaitGroup,Goroutines 似乎還是被中斷了的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:stackoverflow.com。如有侵權,請聯絡admin@php.cn刪除