英文:
When I don't use the go keyword a function doesn't work
问题
在这个函数中,你可以看到我使用了"go"关键字。
package main
import (
"fmt"
"math"
)
func main() {
c := make(chan string)
go findGreatestDivisor(4, c)
for i := 0; i <= 1; i++ {
fmt.Println(<-c)
}
}
func findGreatestDivisor(num float64, c chan string) {
var counter float64 = 10000
for i := 9999; i > 0; i-- {
if math.Mod(num, counter) == 0 {
fmt.Println("Check..", math.Mod(4, 1))
c <- fmt.Sprintf("%f is divisible by %d", num, i)
}
counter--
}
}
它可以正常工作,给我返回了最大的整数。但是当我删除了调用函数时的"go"关键字,只留下下面这行代码:
findGreatestDivisor(4, c)
它会报错:
fatal error: all goroutines are asleep - deadlock!
goroutine 1 [chan send]: main.findGreatestDivisor(0x4010000000000000, 0xc82001a0c0)
/home/ubuntu/workspace/test.go:21 +0x37c main.main()
/home/ubuntu/workspace/test.go:10 +0x61 exit status 2
为什么会这样呢?
英文:
In this function you can see that I use the go keyword.
package main
import (
"fmt"
"math"
)
func main() {
c := make(chan string)
go findGreatestDivisor(4, c)
for i := 0; i <= 1; i++ {
fmt.Println(<-c)
}
}
func findGreatestDivisor(num float64, c chan string) {
var counter float64 = 10000
for i := 9999; i > 0; i-- {
if math.Mod(num, counter) == 0 {
fmt.Println("Check..", math.Mod(4, 1))
c <- fmt.Sprintf("%f is divisble by %d", num, i)
}
counter--
}
}
It works. It gives me the largest integer. But now I get curious and delete the go keyword where I called the function here
go findGreatestDivisor(4,c)
When i just do
findGreatestDivisor(4,c)
it gives me the error
fatal error: all goroutines are asleep - deadlock!
goroutine 1 [chan send]: main.findGreatestDivisor(0x4010000000000000,
0xc82001a0c0)
/home/ubuntu/workspace/test.go:21 +0x37c main.main()
/home/ubuntu/workspace/test.go:10 +0x61 exit status 2
Why is that?
答案1
得分: 2
《Go编程语言规范》
发送语句
发送语句在通道上发送一个值。通道表达式必须是通道类型,通道方向必须允许发送操作,并且要发送的值的类型必须可赋值给通道的元素类型。
SendStmt = Channel "<-" Expression .
Channel = Expression .
在通信开始之前,通道和值表达式都会被求值。通信会阻塞,直到发送可以进行。在无缓冲通道上的发送可以进行,如果有接收者准备好的话。在有缓冲通道上的发送可以进行,如果缓冲区中有空间。在关闭的通道上发送会导致运行时恐慌。在空通道上发送会永远阻塞。
ch <- 3 // 将值3发送到通道ch
在 findGreatestDivisor
中
c := make(chan string)
findGreatestDivisor(4,c)
你试图在无缓冲通道 c
上发送
c <- fmt.Sprintf("%f is divisble by %d", num, i)
但是通信会阻塞,直到发送可以进行。在无缓冲通道上的发送可以进行,如果有接收者准备好的话。现在没有准备好的接收者。
对通道 c
的接收
fmt.Println(<-c)
直到从 findGreatestDivisor
返回后才会准备好。那时已经太晚了。
英文:
> The Go Programming Language Specification
>
> Send statements
>
> A send statement sends a value on a channel. The channel expression
> must be of channel type, the channel direction must permit send
> operations, and the type of the value to be sent must be assignable to
> the channel's element type.
>
> SendStmt = Channel "<-" Expression .
> Channel = Expression .
>
> Both the channel and the value expression are evaluated before
> communication begins. Communication blocks until the send can proceed.
> A send on an unbuffered channel can proceed if a receiver is ready. A
> send on a buffered channel can proceed if there is room in the buffer.
> A send on a closed channel proceeds by causing a run-time panic. A
> send on a nil channel blocks forever.
>
> ch <- 3 // send value 3 to channel ch
In findGreatestDivisor
c := make(chan string)
findGreatestDivisor(4,c)
you try to send on the unbuffered channel c
c <- fmt.Sprintf("%f is divisble by %d", num, i)
but communication blocks until the send can proceed. A send on an unbuffered channel can proceed if a receiver is ready. There is no receiver ready.
The receives on channel c
fmt.Println(<-c)
won't be ready until after you return from findGreatestDivisor
. That's too late.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论