在Go语言中并行快速排序中的死锁问题

huangapple go评论104阅读模式
英文:

Deadlock in parallel quicksort in Go

问题

作为练习,我正在尝试在Go中实现快速排序的并行版本。这是我目前的代码:

  1. func quicksort(nums []int, ch chan int, level int, threads int) {
  2. level *= 2;
  3. if len(nums) == 1 { ch<- nums[0]; close(ch); return }
  4. less := make([]int, 0)
  5. greater := make([]int,0)
  6. pivot := nums[0]
  7. nums = nums[1:]
  8. for _,i := range nums{
  9. switch{
  10. case i <= pivot:
  11. less = append(less,i)
  12. case i > pivot:
  13. greater = append(greater,i)
  14. }
  15. }
  16. ch1 := make(chan int, len(less))
  17. ch2 := make(chan int, len(greater))
  18. if(level <= threads){
  19. go quicksort(less, ch1, level, threads)
  20. go quicksort(greater,ch2, level, threads)
  21. }else{
  22. quicksort(less,ch1, level, threads)
  23. quicksort(greater,ch2, level, threads)
  24. }
  25. for i := range ch1{
  26. ch<-i;
  27. }
  28. ch<-pivot
  29. for i := range ch2{
  30. ch<-i;
  31. }
  32. close(ch)
  33. return
  34. }

然而,当我运行它时,我得到一个错误,声称程序已经死锁!我对导致这个问题感到困惑...

提前感谢,

Linus

英文:

As an exercise I'm trying to implement a parallel version of quicksort in Go. This is what I have so far:

  1. func quicksort(nums []int, ch chan int, level int, threads int) {
  2. level *= 2;
  3. if len(nums) == 1 { ch&lt;- nums[0]; close(ch); return }
  4. less := make([]int, 0)
  5. greater := make([]int,0)
  6. pivot := nums[0]
  7. nums = nums[1:]
  8. for _,i := range nums{
  9. switch{
  10. case i &lt;= pivot:
  11. less = append(less,i)
  12. case i &gt; pivot:
  13. greater = append(greater,i)
  14. }
  15. }
  16. ch1 := make(chan int, len(less))
  17. ch2 := make(chan int, len(greater))
  18. if(level &lt;= threads){
  19. go quicksort(less, ch1, level, threads)
  20. go quicksort(greater,ch2, level, threads)
  21. }else{
  22. quicksort(less,ch1, level, threads)
  23. quicksort(greater,ch2, level, threads)
  24. }
  25. for i := range ch1{
  26. ch&lt;-i;
  27. }
  28. ch&lt;-pivot
  29. for i := range ch2{
  30. ch&lt;-i;
  31. }
  32. close(ch)
  33. return
  34. }

However, when I run it, I get an error claiming the program has deadlocked! I'm pretty stumped to what is causing this...

Thanks in advance,

Linus

答案1

得分: 3

代码有一个问题,至少有一个潜在的错误使用情况:

  1. 缺少基本情况。考虑如果quicksort被要求对空切片进行排序会发生什么。
  2. 当第一次调用quicksort,比如在main()中,如果不在一个单独的goroutine中启动排序器,主线程运行顶层排序时可能会阻塞,尝试写回到通道(取决于顶层通道本身是否有缓冲区)。

例如:

  1. func main() {
  2. x := []int{3, 1, 4, 1, 5, 9, 2, 6}
  3. ch := make(chan int)
  4. quicksort(x, ch, 0, 0) // 有错误!
  5. for v := range(ch) {
  6. fmt.Println(v)
  7. }
  8. }

这是有错误的,因为它要求主线程进行排序,但它最终会在quicksort的这部分代码中阻塞:它无法与自己通信!

  1. for i := range ch1{
  2. ch<-i;
  3. }

在这里向顶层通道写入时,主线程将发生死锁。

与此相反,如果我们在顶层创建一个goroutine,情况会有所不同:

  1. func main() {
  2. x := []int{3, 1, 4, 1, 5, 9, 2, 6}
  3. ch := make(chan int)
  4. go quicksort(x, ch, 0, 0)
  5. for v := range(ch) {
  6. fmt.Println(v)
  7. }
  8. }

现在我们避免了特定的死锁问题。

英文:

The code has one problem, and at least one potential buggy usage case:

  1. It is missing a base case. Consider what happens if quicksort is asked to sort the empty slice.
  2. When calling quicksort for the first time, say in a main(), if you don't spawn the sorter in a separate goroutine, the main thread, running the toplevel sort, can block trying to write back to the channel (depending if the toplevel channel itself is buffered).

For example:

  1. func main() {
  2. x := []int{3, 1, 4, 1, 5, 9, 2, 6}
  3. ch := make(chan int)
  4. quicksort(x, ch, 0, 0) // buggy!
  5. for v := range(ch) {
  6. fmt.Println(v)
  7. }
  8. }

This is buggy because this asks the main thread to do the sort, but it will inevitably block at this part of quicksort: it can't communicate with itself!

  1. for i := range ch1{
  2. ch&lt;-i;
  3. }

and it's at the write to the toplevel channel here that the main thread will deadlock.

Contrast this with what happens if we do create a goroutine at toplevel:

  1. func main() {
  2. x := []int{3, 1, 4, 1, 5, 9, 2, 6}
  3. ch := make(chan int)
  4. go quicksort(x, ch, 0, 0)
  5. for v := range(ch) {
  6. fmt.Println(v)
  7. }
  8. }

and now we avoid that particular deadlock problem.

huangapple
  • 本文由 发表于 2013年6月7日 23:20:51
  • 转载请务必保留本文链接:https://go.coder-hub.com/16987606.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定