当我不使用”go”关键字时,函数无法正常工作。

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

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 (
	&quot;fmt&quot;
	&quot;math&quot;
)

func main() {
	c := make(chan string)
	go findGreatestDivisor(4, c)
	for i := 0; i &lt;= 1; i++ {
		fmt.Println(&lt;-c)
	}
}

func findGreatestDivisor(num float64, c chan string) {
	var counter float64 = 10000
	for i := 9999; i &gt; 0; i-- {
		if math.Mod(num, counter) == 0 {
			fmt.Println(&quot;Check..&quot;, math.Mod(4, 1))
			c &lt;- fmt.Sprintf(&quot;%f is divisble by %d&quot;, 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 &lt;- fmt.Sprintf(&quot;%f is divisble by %d&quot;, 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(&lt;-c)

won't be ready until after you return from findGreatestDivisor. That's too late.

huangapple
  • 本文由 发表于 2016年3月20日 09:22:00
  • 转载请务必保留本文链接:https://go.coder-hub.com/36109239.html
匿名

发表评论

匿名网友

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

确定