实现堆排列算法时,Golang 范围内的 channel 具有奇怪的行为

标签 go range permutation channel heaps-algorithm

我试图实现 Heap's Algorithm在使用 channel 。当仅在屏幕上打印 slice 时,下面的代码工作正常,但是当使用 channel 将数组传递到主函数上的 for/range 循环时,会发生一些意外行为,并且 slice/数组以重复的方式打印,并且并非所有排列都被打印。发送。我想也许我会在主函数能够打印结果之前关闭 channel ,但我不希望出现双重打印。为什么会发生这种情况以及我怎样才能让它发挥作用。

package main

import "fmt"

func perm(a []int64) {
    var n = len(a)
    var c = make([]int, n)
    fmt.Println(a)
    i := 0
    for i < n {
        if c[i] < i {
            if i%2 == 0 {
                a[0], a[i] = a[i], a[0]
            } else {
                a[c[i]], a[i] = a[i], a[c[i]]
            }
            fmt.Println(a)
            c[i]++
            i = 0
        } else {
            c[i] = 0
            i++
        }
    }
}

func permch(a []int64, ch chan<- []int64) {
    var n = len(a)
    var c = make([]int, n)
    ch <- a
    i := 0
    for i < n {
        if c[i] < i {
            if i%2 == 0 {
                a[0], a[i] = a[i], a[0]
            } else {
                a[c[i]], a[i] = a[i], a[c[i]]
            }
            ch <- a
            c[i]++
            i = 0
        } else {
            c[i] = 0
            i++
        }
    }
    close(ch)
}

func main() {
    var i = []int64{1, 2, 3}
    fmt.Println("Without Channels")
    perm(i)
    ch := make(chan []int64)
    go permch(i, ch)
    fmt.Println("With Channels")
    for slc := range ch {
        fmt.Println(slc)
    }

}

最佳答案

您的问题是 slice 是引用类型,并且正在多个 goroutine 中访问。在 perm 中,您在每一步完成处理后直接打印 a。在 permch 中,您通过 channel 发送 a,但随后立即开始再次修改它。由于通过 channel 发送的每个 slice 都引用相同的底层数组,因此您会遇到竞争条件,即下一次循环迭代是否会更改 main 中的 aPrintln() 调用首先到达该数组。

一般来说,如果您在任何使用 goroutine 的程序中遇到意外行为,则可能存在竞争条件。使用 -race 标志运行程序以查看位置。

编辑:此外,关闭 channel 不会影响 channel 的例行读取操作。可以继续读取 channel ,直到其缓冲区为空,此时它将开始返回该类型的零值。仅当 channel 关闭并且其缓冲区为空时, channel 上的范围循环才会终止。

关于实现堆排列算法时,Golang 范围内的 channel 具有奇怪的行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43722558/

相关文章:

go - 如何在json中按深层排序在mongo中获取20个文档?

go - 在Golang web应用开发中,是否可以将Go的模板与jade(pug)模板引擎一起使用?

Matlab:从一定范围内不重复的随机整数

将任务分配给人员的算法,其中某些任务需要多人,并且没有人会执行同一任务两次

java - 从 Java 中的列表创建不同的排列

lua - Torch:如何按行对张量进行洗牌?

go - 返回可选值和错误

go - 如何在 Go 结构(golang)中存储 unicode

reference - Go:你可以使用 range 和 slice 但得到引用吗? (迭代)

excel - 动态 RTD 数据记录到另一张纸上