英文:
Func will not run; increment channel
问题
我正在写一个函数,尝试对一个通道进行递增操作。在一个更大的程序中,这个操作不起作用,实际上会在以下代码行上停顿:
current = <-channel
go func
正在运行,但程序似乎在这一行上停止。
我尝试编写一个更小的 SSCCE(Short, Self Contained, Correct (Compilable), Example)示例,但现在我遇到了不同的问题。以下是示例代码:
package main
import (
"fmt"
)
func main() {
count := make(chan int)
go func(count chan int) {
current := 0
for {
current = <-count
current++
count <- current
fmt.Println(count)
}
}(count)
}
然而,在上面的示例中,go func
似乎根本没有被调用。如果我在for {
之前放置一个fmt.Println
语句,它不会打印出来。如果我在go func
块之前或之后放置fmt.Println
语句,它们都会打印出来。
- 为什么上面的示例中的自调用块似乎根本没有运行?
- 如果它正在运行,为什么会在
current = <-count
上阻塞?如何正确地对通道进行递增操作?
英文:
I'm writing a function where I'm trying to increment a channel. In a much larger program, this is not working and it actually hangs on a line that looks like:
current = <-channel
The go func
s are running, but the program seems to halt on this line.
I tried to write a smaller SSCCE, but now I'm having a different problem. Here it is:
package main
import (
"fmt"
)
func main() {
count := make(chan int)
go func(count chan int) {
current := 0
for {
current = <-count
current++
count <- current
fmt.Println(count)
}
}(count)
}
However, in the above the go func
does not actually seem to be called at all. If I put a fmt.Println
statement before for {
, it does not print out. If I put fmt.Println
statements before or after they go func
block, they will both print out.
- Why does the self-calling block in the above example not seem to run at all?
- If it were running, why would it block on
current = <-count
? How could I properly increment the channel?
答案1
得分: 1
我无法回答第一个问题,因为需要更多信息。你展示的代码有两个问题。首先,在启动goroutine之后,程序就退出了。第二个问题是,goroutine在等待count通道接收到内容,如果你从count通道接收到内容,它就不会发生死锁。
下面是一个展示死锁的示例(http://play.golang.org/p/cRgjZt7U2A):
package main
import (
"fmt"
)
func main() {
count := make(chan int)
go func() {
current := 0
for {
current = <-count
current++
count <- current
fmt.Println(count)
}
}()
fmt.Println(<-count)
}
下面是一个展示按照你期望的方式工作的示例(http://play.golang.org/p/QQnRpCDODu):
package main
import (
"fmt"
)
func main() {
count := make(chan int)
go func() {
current := 0
for {
current = <-count
current++
count <- current
fmt.Println(count)
}
}()
count <- 1
fmt.Println(<-count)
}
以上是翻译好的内容,请确认是否满意。
英文:
I can't answer the first one issue without more info. The code you did show has two issues. First, the program exits after the goroutine is started. The second issue is that the goroutine is waiting for something to be sent to count, if you receive from the count channel it will not deadlock.
Here is an example showing the deadlock (http://play.golang.org/p/cRgjZt7U2A):
package main
import (
"fmt"
)
func main() {
count := make(chan int)
go func() {
current := 0
for {
current = <-count
current++
count <- current
fmt.Println(count)
}
}()
fmt.Println(<-count)
}
Here is an example of it working the way I think you are expecting (http://play.golang.org/p/QQnRpCDODu)
package main
import (
"fmt"
)
func main() {
count := make(chan int)
go func() {
current := 0
for {
current = <-count
current++
count <- current
fmt.Println(count)
}
}()
count <- 1
fmt.Println(<-count)
}
答案2
得分: 0
通道:通道是一种不能存储值的东西。它只能缓冲值,所以基本用法是可以发送和接收值。因此,当你声明count := make(chan int)
时,它不包含任何值。所以语句current = <-count
会给你一个错误,说所有的Go协程都处于休眠状态。基本上,通道的设计是为了作为运行在不同进程上的不同Go协程之间的通信器,而你的主函数是在不同进程上运行的。
所以你对第一个问题的答案是:
1.为什么上面的自调用块似乎根本没有运行?
答案-看看你运行的主函数有一个进程,而Go协程在另一个进程上运行,所以如果你的主函数在Go协程之前执行完成,那么你将永远不会从Go协程中得到结果,因为主线程在执行完成后就会死掉。所以我给你提供一个与你递增计数器的示例相关的Web示例。在这个示例中,你将创建一个服务器并监听端口8000。首先运行这个示例,然后在你的Web浏览器中输入localhost:8000,它将显示通道在每个缓冲区中存储的递增计数器。这个示例将给你一个关于通道如何工作的想法。
2.如果它正在运行,为什么会在current = <-count
上阻塞?我该如何正确递增通道?
答案-你正在从通道接收,但通道在其缓冲区中没有任何内容,所以你会得到一个错误"所有的Go协程都处于休眠状态"。首先,你应该将值传递到通道中,并相应地接收它,否则它将再次进入死锁状态。
package main
import (
"fmt"
"http"
)
type webCounter struct {
count chan int
}
func NewCounter() *webCounter {
counter := new(webCounter)
counter.count = make(chan int, 1)
go func() {
for i:=1 ;; i++ { counter.count <- i }
}()
return counter
}
func (w *webCounter) ServeHTTP(r http.ResponseWriter, rq *http.Request) {
if rq.URL.Path != "/" {
r.WriteHeader(http.StatusNotFound)
return
}
fmt.Fprintf(r, "You are visitor %d", <-w.count)
}
func main() {
http.ListenAndServe(":8000", NewCounter());
}
英文:
Channel :- Channel is something that can't store the value. It can only buffer the value so the basic usage is it can send and receive the value. So when you declare count := make(chan int) it does not contain any value. So the statement current = <-count will give you error that all go routines are asleep. Basically channel was design to work as communicator for different go routines which are running on different process and your main function is running on different process.
So your answer to first question is:-
1.Why does the self-calling block in the above example not seem to run at all?
Answer- See the main function you are running has one process and the go routine is running on another process so if your main function gets its execution completed before your go-routine than you will never get result form go-routine because your main thread gets dead after the execution is complete. So i am providing you a web example which is related to your example of incrementing the counter. In this example you will create a server and listen on port 8000.First of all run this example and go in your web browser and type localhost:8000 and it will so you the incrementing counter that channel stores in every buffer. This example will provide you an idea of how channel works.
2.If it were running, why would it block on current = <-count? How could I properly increment the channel?
Answer-You are receiving from the channel but channel does not have anything in its buffer so you will get an error "All go-routines are asleep". First you should transfer value into the channel and correspondingly receive it otherwise it will again go to deadlock.
package main
import (
"fmt"
"http"
)
type webCounter struct {
count chan int
}
func NewCounter() *webCounter {
counter := new(webCounter)
counter.count = make(chan int, 1)
go func() {
for i:=1 ;; i++ { counter.count <- i }
}()
return counter
}
func (w *webCounter) ServeHTTP(r http.ResponseWriter, rq *http.Request) {
if rq.URL.Path != "/" {
r.WriteHeader(http.StatusNotFound)
return
}
fmt.Fprintf(r, "You are visitor %d", <-w.count)
}
func main() {
http.ListenAndServe(":8000", NewCounter());
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论