下面是一个启动外部进程的函数,将正则表达式与进程的标准输出进行匹配,并返回匹配的内容。
func (c *Colony) startCircuit(peer *string) (string, error) {
var (
err error
cmd *exec.Cmd
anchorChan chan string
)
// ... (omitted for readability)
// get the anchor from standard output
go func() {
defer out.Close()
anchorChan = make(chan string)
for scanner := bufio.NewScanner(out); scanner.Scan(); {
line := scanner.Text()
if anchor := reRootAnchor.FindString(line); anchor != "" {
log.Println("Started circuit server with anchor:", anchor)
anchorChan <- anchor
break
}
}
}()
anchor := <-anchorChan
return anchor, err
}
运行该函数时,我获得了以下输出,表明确实找到了匹配并且(可能)被推入anchorChan
:
2016/05/22 14:04:36 Started circuit server with anchor: circuit://[::]:36195/20666/Q431cc5fe613aa04b
然而,startCircuit
的来电者似乎挂了。以下是相关的代码:
rootAnchor, err := c.startCircuit(peer)
if err != nil {
return "", err
}
log.Fatal(rootAnchor) // DEBUG
为什么startCircuit
无限期悬挂而不是返回?
答案 0 :(得分:5)
问题其实很简单。提示:以下代码以死锁结尾。
package main
import "fmt"
func main() {
var c chan string
go func() {
c = make(chan string)
c <- "42"
}()
str := <-c
fmt.Println(str)
}
从那里,问题是微不足道的。启动goroutine时,您的频道未初始化。有两个goroutines的比赛,显然无法决定哪个应该优先考虑。
所以,你的答案是:在goroutine开始之前调用make(chan ...)
,它应该解决你的问题。在effective go.
答案 1 :(得分:0)
Dave Cheney有一篇很好的相关博文:http://dave.cheney.net/2014/03/19/channel-axioms
最相关的观点:
由于未初始化的通道为零,因此对它的任何读写都将导致死锁。例如,在T. Claverie的回答中,有一个竞赛:如果c = make(chan string)
,(和c <- "42"
,我认为str := <-c
必须在这一点等待)先发生,然后接收发生从初始化的非空通道,一切运行良好:
package main
import "fmt"
import "time"
func main() {
var c chan string
go func() {
c = make(chan string)
c <- "42"
}()
time.Sleep(time.Second * 1)
str := <-c
fmt.Println(str)
}
您可以运行上面的示例来说服自己。 (这不是好的做法,甚至保证每次都能奏效。)
但是,如果首先发生str := <-c
,那么您将从nil
频道收到,这会导致死锁。