Go编程语言代码错误

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

Go Programming Language Code Error

问题

我试着用GO语言写一个简单的代码,在这个代码中有两个Go协程(Send和Receive),它们互相发送整数。我给出了下面的代码。有人可以帮我解释为什么这个程序的输出是[没有输出]吗?有没有什么愚蠢的错误(对不起,我是GO的新手)?

package main

func Send(in1 <-chan int, out1 chan<- int) {

    i := 2
    out1 <- i
    print(i, "\n")
}

func Receive(in <-chan int, out chan<- int) {

    i := <-in
    print(i, "\n")
    out <- i
}

func main() {

    for i := 0; i < 10; i++ {
        ch1 := make(chan int)
        ch := make(chan int)
        go Send(ch1, ch)
        go Receive(ch, ch1)
        ch = ch1
        ch1 = ch
    }
}
英文:

I try to write a simple code in GO, in which two go routine (Send and Receive) send each other integers. I give the code below. Can anybody help me why the output of this program is [no output]. Is there any silly mistake (sorry, I am new in GO) ?

package main

func Send (in1 &lt;-chan int, out1 chan&lt;- int) {

                i := 2 
		out1 &lt;- i 
	print(i, &quot;\n&quot;)
}

func Receive (in &lt;-chan int, out chan&lt;- int) {

		i := &lt;-in 
		print(i, &quot;\n&quot;)
		out &lt;- i 
}


func main() {

	   for i := 0; i &lt; 10; i++ {
		ch1 := make(chan int)
		ch := make(chan int) 
	        go Send (ch1 , ch)
		go Receive (ch , ch1)
		ch = ch1
		ch1 = ch
		}
	
}

答案1

得分: 2

这是一个使用Go语言编写的程序。它包含了两个函数Send和Receive,以及一个主函数main。Send函数向通道ch发送数字,Receive函数从通道ch接收数字。在主函数中,我们创建了一个通道ch,并使用go关键字在一个新的goroutine中调用Receive函数,然后在主goroutine中调用Send函数。

当我在golang.org上运行这个程序时,输出如下:

0 sending
0 received
1 sending
2 sending
1 received
2 received
3 sending
4 sending
3 received
4 received
5 sending
6 sending
5 received
6 received
7 sending
8 sending
7 received
8 received
9 sending

我不确定为什么没有接收到数字9。应该有一种方法来使主线程等待Receive goroutine完成。此外,发送者和接收者都知道它们将发送10个数字,这不够优雅。其中一个goroutine应该在另一个完成工作后关闭。我不确定如何做到这一点。

EDIT1:

这是一个使用两个通道的实现,两个goroutine之间相互发送整数。其中一个被指定为响应者,只有在接收到整数后才发送整数。响应者只是将接收到的整数加2,然后发送回去。

当我在golang.org上运行这个程序时,输出如下:

0 command
2 response
1 command
3 response
2 command
4 response
3 command
5 response
4 command
6 response
5 command
7 response
6 command
8 response
7 command
9 response
8 command
10 response
9 command
11 response
英文:

How about this:

package main

func Send (ch chan&lt;- int) {
    for i := 0; i &lt; 10; i++ {
      print(i, &quot; sending\n&quot;)
      ch &lt;- i
    }
}

func Receive (ch &lt;-chan int) {
    for i := 0; i &lt; 10; i++ {
        print(&lt;-ch, &quot; received\n&quot;)
    }
}

func main() {
   ch := make(chan int)
   go Receive(ch)
   Send(ch)
}

The output of this when I run it on golang.org is:

0 sending
0 received
1 sending
2 sending
1 received
2 received
3 sending
4 sending
3 received
4 received
5 sending
6 sending
5 received
6 received
7 sending
8 sending
7 received
8 received
9 sending

I'm not sure why the 9 was never received. There should be some way to sleep the main thread until the Receive goroutine has completed. Also, it's inelegant that the receiver and the sender both know that they are going to send 10 numbers. One of the goroutines should just shut off when the other has finished its work. I'm not sure how to do that.

EDIT1:

Here is an implementation with two channels, and the go routines send ints back and forth between eachother. One is designated as the responder, who only sends and int after it receives an int. The responder simply adds two to the int he receives, and then sends it back.

package main

func Commander(commands chan int, responses chan int) {
    for i := 0; i &lt; 10; i++ {
      print(i, &quot; command\n&quot;)
      commands &lt;- i
      print(&lt;-responses, &quot; response\n&quot;);
    }
    close(commands)
}

func Responder(commands chan int, responses chan int) {
    for {
        x, open := &lt;-commands
        if !open {
            return;
        }
        responses &lt;- x + 2
    }
}

func main() {
   commands := make(chan int)
   responses := make(chan int)
   go Commander(commands, responses)
   Responder(commands, responses)
}

The output when I run it on golang.org is:

0 command
2 response
1 command
3 response
2 command
4 response
3 command
5 response
4 command
6 response
5 command
7 response
6 command
8 response
7 command
9 response
8 command
10 response
9 command
11 response

答案2

得分: 2

David Grayson的修复方法有效,但为什么有时候无法接收到9的解释无法适应于评论!

当发送goroutine在通道上发送值时,它会阻塞直到接收goroutine接收到它。在那时,它就不再阻塞。调度器可能会在给接收goroutine打印任何内容之前立即从main返回。如果将GOMAXPROCS设置为大于1的值,这种情况发生的频率较低,因为接收goroutine在主goroutine活动时不会阻塞。

如果你想要阻止main在所有goroutine完成之前返回,你可以从Receive()返回一个通道,像这样:

package main

import "fmt"

func Send(ch chan<- int) {
    for i := 0; i < 10; i++ {
        fmt.Println(i, " sending")
        ch <- i
    }
    close(ch)
}

func Receive(ch <-chan int) (<-chan bool) {
    done := make(chan bool)
    go func() {
        for {
            i, ok := <-ch
            if !ok {
                break
            }
            fmt.Println(i, " received")
        }
        done <- true
    }()
    return done
}

func main() {
    ch := make(chan int)
    d := Receive(ch)
    Send(ch)
    _ = <-d
}

至于为什么你的原始示例输出为空:你创建了两个goroutine,因此main完全不受阻塞,所以它只是返回并退出程序!我肯定也犯过这个错误,但运行时只会与主goroutine连接,而不是与所有goroutine连接,这可能与你的期望不同。

英文:

David Grayson's fix works, but the explanation of why 9 is not always received wouldn't fit into a comment!

When the sending goroutine sends the value on the channel, it blocks until the receiving goroutine receives it. At that point, it's unblocked. The go scheduler might return from main almost immediately before it gives the receiving goroutine a chance to print anything. If you set GOMAXPROCS to something greater than 1, this happens less frequently because the receiving goroutine won't block while the main goroutine is active.

If you want to stop main from returning until all goroutines are finished, you can return a channel from Receive(), like this:

package main

import &quot;fmt&quot;

func Send(ch chan&lt;- int) {
	for i := 0; i &lt; 10; i++ {
		fmt.Println(i, &quot; sending&quot;)
		ch &lt;- i
	}
	close(ch)
}

func Receive(ch &lt;-chan int) (&lt;-chan bool) {
	done := make(chan bool)
	go func() {
		for {
			i, ok := &lt;-ch
			if !ok {
				break
			}
			fmt.Println(i, &quot; received&quot;)
		}
		done &lt;- true
	}()
	return done
}

func main() {
	ch := make(chan int)
	d := Receive(ch)
	Send(ch)
	_ = &lt;-d
}

As for why your output was empty in your original example: you make two goroutines, and thus main is totally unblocked, so it just returns and the program exits! I've definitely made this mistake too, but the runtime only joins with the main goroutine, not with ALL goroutines, like you may expect.

huangapple
  • 本文由 发表于 2011年11月22日 23:46:17
  • 转载请务必保留本文链接:https://go.coder-hub.com/8229572.html
匿名

发表评论

匿名网友

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

确定