在实现堆时,Golang通过通道的范围具有奇怪的行为';s置换算法
我尝试使用通道在围棋中实现。当仅在屏幕上打印切片时,下面的代码工作正常,但当使用通道将数组传递到主函数上的for/range循环时,会出现一些意外行为,切片/数组以双面打印,并且不会发送所有排列。我想我可能会在主函数能够打印结果之前关闭频道,但我不希望出现双重打印。为什么会发生这种情况,我如何才能让它工作在实现堆时,Golang通过通道的范围具有奇怪的行为';s置换算法,go,range,permutation,slice,channels,Go,Range,Permutation,Slice,Channels,我尝试使用通道在围棋中实现。当仅在屏幕上打印切片时,下面的代码工作正常,但当使用通道将数组传递到主函数上的for/range循环时,会出现一些意外行为,切片/数组以双面打印,并且不会发送所有排列。我想我可能会在主函数能够打印结果之前关闭频道,但我不希望出现双重打印。为什么会发生这种情况,我如何才能让它工作 package main import "fmt" func perm(a []int64) { var n = len(a) var c = make([]int, n)
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)
}
}
主程序包
输入“fmt”
func perm(a[]int64){
var n=len(a)
var c=制造([]整数,n)
fmt.Println(a)
i:=0
对于i func permch(a[]int64,ch chan您的问题是切片是引用类型,并且在多个goroutine中被访问。在perm
中,您在每个步骤完成处理时直接打印a
。在permch
中,您通过通道发送a
,但随后立即开始再次修改它。因为eac通过通道发送的h slice引用相同的底层数组,对于下一次循环迭代是改变a
,还是先调用Println()
通常,如果您在使用goroutines的任何程序中遇到意外行为,则可能存在争用情况。请使用-race
标志运行该程序以查看位置
编辑:此外,关闭通道对通道的例行读取没有影响。可以继续读取通道,直到其缓冲区为空,此时它将开始返回该类型的零值。通道上的范围循环仅在通道关闭且缓冲区为空时终止。permch
在打印main
的同时修改a
,因此您的输出是乱码
我可以想出三个简单的解决办法:
使用互斥锁保护对a
的访问
在频道上放置一份a
:
从它已经打印的main中获得某种返回信号,并且permch
可以继续(不建议这样做,但它可以工作)
第二点很简单:
a2 := make([]int64, len(a))
copy(a2,a)
ch <- a2
a2:=make([]int64,len(a))
副本(a2,a)
你能告诉我如何实现#1或#2吗?我认为在从main到goroutine的信号中添加另一个通道有点麻烦。我尝试过使用内置的copy()
和make()
创建一个新的底层数组,但我认为问题在于主打印数组的同时permch
会改变它。我真的不知道如何使用互斥体,因为我可以锁定permch中正在改变数组的部分,但不能保证它会等待main()
打印数组。当我尝试使用互斥时,我可以使竞争检测器静音,但无法得到我想要的,这是无通道版本的行为。