与 GopherJS 的 goroutine 中的僵局



为什么下面的代码中会出现死锁?我正在尝试将一些东西从goroutine返回到外面

package main
import (
"fmt"
"syscall/js"
"time"
)
func test(this js.Value, i []js.Value) interface{} {
done := make(chan string, 1)
go func() {
doRequest := func(this js.Value, i []js.Value) interface{} {
time.Sleep(time.Second)
return 0
}
js.Global().Set("doRequest", js.FuncOf(doRequest))
args := []js.Value{js.ValueOf("url")}
var x js.Value
doRequest(x, args)
done <- "true"
}()
aa := <-done
fmt.Println(aa)
return 0
}
func main() {
c := make(chan bool)
js.Global().Set("test", js.FuncOf(test))
<-c
}

当我在浏览器上运行它并调用test((时,将显示以下错误

fatal error: all goroutines are asleep - deadlock!
goroutine 1 [chan receive]:
.....

几乎是错误消息中所说的。 所有的侍从都睡着了。main不会启动任何内容,而只是接收一个通道,因此它被阻塞,并且没有其他 goroutines 正在运行,因此main不可能再次唤醒,因此运行时会感到恐慌。

如果我没记错的话,与普通的 Go 不同,GopherJS 不会关闭所有内容并在退出时退出main(部分原因是:这到底意味着什么? 最接近 Go 程序的类比是关闭网页! 这有点糟糕。 所以GopherJS不这样做。 因此,严格来说,在 GopherJS 中,你为保持main活着所做的工作是没有必要的。

也就是说,如果你说(例如(最后time.Sleep(time.Hour),那么当所有 goroutines 仍然处于睡眠状态时(严格来说(,main最终会醒来,运行时知道这一点,所以在这种情况下它不会惊慌失措。

至于您的实际test功能,一旦您尝试了它,您就会收到相关的错误消息:Uncaught Error: runtime error: cannot block in JavaScript callback, fix by wrapping code in goroutine.test在通道上执行阻塞调用,GopherJS不允许直接从Javascript调用的函数中这样做,因此它感到恐慌。 (当我在操场上运行它时,我也得到了Uncaught TypeError: r is not a function,但这只是早期错误的后果。我认为您要做的是等待doRequest完成,打印值并返回,但这不起作用。 为此,您需要使用本机Javascript承诺或其他异步机制。

func main() {
c := make(chan bool)
js.Global().Set("test", js.FuncOf(test))
<-c
}

您已经将通道设为c,然后等待从中接收值。请注意cmain函数的局部变量。对c的引用永远不会在程序的其他任何地方传递,因此永远不会在c通道上发送值,因此您的主 goroutine 将永远等待接收。

最新更新