作为练习,我正在尝试在Go中实现并行版本的quicksort。这就是我到目前为止所做的:
func quicksort(nums []int, ch chan int, level int, threads int) {
level *= 2;
if len(nums) == 1 { ch<- nums[0]; close(ch); return }
less := make([]int, 0)
greater := make([]int,0)
pivot := nums[0]
nums = nums[1:]
for _,i := range nums{
switch{
case i <= pivot:
less = append(less,i)
case i > pivot:
greater = append(greater,i)
}
}
ch1 := make(chan int, len(less))
ch2 := make(chan int, len(greater))
if(level <= threads){
go quicksort(less, ch1, level, threads)
go quicksort(greater,ch2, level, threads)
}else{
quicksort(less,ch1, level, threads)
quicksort(greater,ch2, level, threads)
}
for i := range ch1{
ch<-i;
}
ch<-pivot
for i := range ch2{
ch<-i;
}
close(ch)
return
}
然而,当我运行它时,我得到一个错误声称程序已经死锁!我很难接受造成这种情况的原因......
提前致谢,
莱纳斯
答案 0 :(得分:3)
代码有一个问题,至少有一个潜在的错误使用案例:
quicksort
对空切片进行排序,会发生什么。quicksort
时,在main()
中说,如果不在单独的goroutine中生成分拣机,运行顶层排序的主线程可以阻止尝试写回通道(取决于顶层通道本身是否被缓冲)。例如:
func main() {
x := []int{3, 1, 4, 1, 5, 9, 2, 6}
ch := make(chan int)
quicksort(x, ch, 0, 0) // buggy!
for v := range(ch) {
fmt.Println(v)
}
}
这是错误的,因为这要求主线程进行排序,但它将不可避免地阻塞quicksort
的这一部分:它无法与自身通信!
for i := range ch1{
ch<-i;
}
并且在写入toplevel通道时,主线程将死锁。
将此与我们在顶层创建goroutine时发生的情况进行对比:
func main() {
x := []int{3, 1, 4, 1, 5, 9, 2, 6}
ch := make(chan int)
go quicksort(x, ch, 0, 0)
for v := range(ch) {
fmt.Println(v)
}
}
现在我们避免了特定的死锁问题。