Func不会运行;增量通道

时间:2014-02-07 00:01:33

标签: concurrency go mutex channel goroutine

我正在编写一个函数,我正在尝试增加一个频道。在一个更大的程序中,这不起作用,它实际上挂在一行看起来像:

current = <-channel

go func正在运行,但程序似乎停在此行上。

我试着写一个较小的SSCCE,但现在我遇到了另一个问题。这是:

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实际上似乎根本没有被调用。如果我在fmt.Println之前添加for {语句,则不会打印出来。如果我在fmt.Println阻止之前或之后放置go func个语句,它们都会打印出来。

  1. 为什么上例中的自调用块似乎根本不运行?
  2. 如果它正在运行,为什么会阻止current = <-count?我怎样才能正确增加频道?

2 个答案:

答案 0 :(得分:1)

如果没有更多信息,我无法回答第一个问题。您展示的代码有两个问题。首先,程序在goroutine启动后退出。第二个问题是goroutine正在等待发送计数的东西,如果你从计数通道收到它就不会死锁。

以下是显示死锁(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)
}

答案 1 :(得分:0)

频道: - 频道无法存储该值。它只能缓冲值,因此基本用法是它可以发送和接收值。因此,当您声明count:= make(chan int)时,它不包含任何值。所以语句current =&lt; -count会给你错误,所有的例程都是睡着的。基本上,channel设计为不同的go例程的通信器,它们运行在不同的进程上,而你的主要功能是在不同的进程上运行。

所以你对第一个问题的回答是: -

1.为什么上面例子中的自调用块似乎根本不运行?

回答 - 看到你正在运行的主要功能有一个进程,而go例程正在另一个进程上运行,所以如果你的main函数在你的例程之前完成它的执行比你永远不会得到的那样结果形成go-routine,因为你的主线程在执行完成后死了。所以我为您提供了一个与您递增计数器示例相关的Web示例。在这个例子中,您将创建一个服务器并侦听端口8000.首先运行此示例并进入Web浏览器并键入localhost:8000,这样您将获得通道存储在每个缓冲区中的递增计数器。此示例将为您提供通道如何工作的概念。

2.如果它正在运行,为什么它会阻塞current =&lt; -count?我怎样才能正确增加频道?

答案 - 您正在从频道收到频道,但频道的缓冲区中没有任何内容,因此您将收到错误“所有正常例程都已入睡”。首先,您应该将值传输到通道中并相应地接收它,否则它将再次陷入死锁。

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());
}