我正在编写一个程序,根据用户输入计算黎曼和。程序会将函数分成1000个矩形(是的,我知道我还没有得到那个数学)并总结它们并返回答案。我正在使用go例程计算1000个矩形,但我得到了一个
fatal error: all go routines are asleep - deadlock!
处理多个go例程的正确方法是什么?我一直在环顾四周,还没有看到一个类似于我案例的例子?我是新手,想要遵守标准。这是我的代码(如果你想看看它的典型用例是什么,它是可以运行的 - 但它确实会破坏)
package main
import "fmt"
import "time"
//Data type to hold 'part' of function; ie. "4x^2"
type Pair struct {
coef, exp int
}
//Calculates the y-value of a 'part' of the function and writes this to the channel
func calc(c *chan float32, p Pair, x float32) {
val := x
//Raise our x value to the power, contained in 'p'
for i := 1; i < p.exp; i++ {
val = val * val
}
//Read existing answer from channel
ans := <-*c
//Write new value to the channel
*c <- float32(ans + (val * float32(p.coef)))
}
var c chan float32 //Channel
var m map[string]Pair //Map to hold function 'parts'
func main() {
c = make(chan float32, 1001) //Buffered at 1001
m = make(map[string]Pair)
var counter int
var temp_coef, temp_exp int
var check string
var up_bound, low_bound float32
var delta float32
counter = 1
check = "default"
//Loop through as long as we have no more function 'parts'
for check != "n" {
fmt.Print("Enter the coefficient for term ", counter, ": ")
fmt.Scanln(&temp_coef)
fmt.Print("Enter the exponent for term ", counter, ": ")
fmt.Scanln(&temp_exp)
fmt.Print("Do you have more terms to enter (y or n): ")
fmt.Scanln(&check)
fmt.Println("")
//Put data into our map
m[string(counter)] = Pair{temp_coef, temp_exp}
counter++
}
fmt.Print("Enter the lower bound: ")
fmt.Scanln(&low_bound)
fmt.Print("Enter the upper bound: ")
fmt.Scanln(&up_bound)
//Calculate the delta; ie. our x delta for the riemann sum
delta = (float32(up_bound) - float32(low_bound)) / float32(1000)
//Make our go routines here to add
for i := low_bound; i < up_bound; i = i + delta {
//'counter' is indicative of the number of function 'parts' we have
for j := 1; j < counter; j++ {
//Go routines made here
go calc(&c, m[string(j)], i)
}
}
//Wait for the go routines to finish
time.Sleep(5000 * time.Millisecond)
//Read the result?
ans := <-c
fmt.Print("Answer: ", ans)
}
答案 0 :(得分:5)
它死锁,因为calc()
和main()
函数都会在任何人写入之前从通道读取。
所以你最终会在每个(非主要的)例行程序中阻止:
ans := <-*c
等待其他人去例行程序向频道输入值。因此,他们都没有到达他们实际写入频道的下一行。 main()
例程将阻止:
ans := <-c
每个人都在等待=死锁
使用缓冲频道
您的解决方案应该只有calc()
函数写入通道,而main()
可以在for-range
循环中读取它,总结来自go-routines的值
您还需要为main()
添加一种方法,以便知道何时不会有更多值到达,可能使用sync.WaitGroup
(可能不是最好的,因为main
isn不想等待,而是总结一下)或普通的柜台。
使用共享内存
有时它不一定是您需要的频道。拥有使用更新的共享值(原子添加对浮点数无效)锁定sync/atomic
包sync.Mutex
也可以正常工作。