这是我对并发合并排序的尝试。我首先非并发地编写并测试了它,所以问题与合并排序逻辑无关,而是与我如何使用 goroutine/channels 有关。
当我运行该程序时,它挂起几秒钟,然后收到信号:killed。
package main
import (
"fmt"
)
func merge(a []int, b []int) []int {
var aCounter int = 0
var bCounter int = 0
var newArray []int = []int{}
for aCounter < len(a) || bCounter < len(b) {
if aCounter >= len(a) {
newArray = append(newArray, b[bCounter])
bCounter++
} else if bCounter >= len(b) {
newArray = append(newArray, a[aCounter])
aCounter++
} else {
if a[aCounter] < b[bCounter] {
newArray = append(newArray, a[aCounter])
aCounter++
} else {
newArray = append(newArray, b[bCounter])
bCounter++
}
}
}
return newArray
}
func mergeSort(arr []int, c chan []int) {
if len(arr) == 1 {
c <- arr
}
firstHalfChan := make(chan []int)
secondHalfChan := make(chan []int)
go mergeSort(arr[0:len(arr)/2], firstHalfChan)
go mergeSort(arr[len(arr)/2:len(arr)], secondHalfChan)
firstHalf, secondHalf := <-firstHalfChan, <-secondHalfChan
c <- merge(firstHalf, secondHalf)
}
func main() {
s := []int{10, 3, 8, 1, 2, 9}
channel := make(chan []int)
go mergeSort(s, channel)
sorted := <- channel
fmt.Println(sorted)
}
但是,如果我向 mergeSort 的基本情况添加 fmt 调用,它实际上会打印所有预期值,然后打印合并排序的正确结果,并无错误地退出。
func mergeSort(arr []int, c chan []int) {
if len(arr) == 1 {
fmt.Println(arr) // ADDED
c <- arr
}
firstHalfChan := make(chan []int)
secondHalfChan := make(chan []int)
go mergeSort(arr[0:len(arr)/2], firstHalfChan)
go mergeSort(arr[len(arr)/2:len(arr)], secondHalfChan)
firstHalf, secondHalf := <-firstHalfChan, <-secondHalfChan
c <- merge(firstHalf, secondHalf)
}
任何人都可以解释这种行为吗?如果我做错了什么,请解释一下是什么?
问题是,当我将代码更改为使用通道而不是返回值时,我忽略了它现在会执行发送到通道的代码,这与返回语句不同,它会在函数中的该点之后停止代码执行.
修复方法是添加一个返回到基本情况:
if len(arr) == 1 {
c <- arr
return
}
fmt 语句“起作用”,因为它在无休止地生成更多 goroutine 之前为此调用添加了延迟,从而允许主线程在内存耗尽之前获取其结果并终止。