GopherJS 在 goroutine 中的死锁
Deadlock in goroutine with GopherJS
为什么下面的代码会出现死锁?我正在尝试 return 从 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]:
.....
func main() {
c := make(chan bool)
js.Global().Set("test", js.FuncOf(test))
<-c
}
您已经创建了一个通道 c
,然后等待从中接收值。请注意 c
是 main
函数的局部变量。对 c
的引用永远不会在程序中的任何其他地方传递,因此 c
通道上永远不会发送值,因此您的主 goroutine 将永远等待接收。
与错误消息中的内容差不多。所有的协程都在睡觉。 main
不启动任何东西,只是接收一个通道,所以它被阻塞了,并且没有其他 goroutines 运行ning,所以 main
不可能再次醒来,所以运行时间恐慌。
如果我没记错的话,与常规 Go 不同,如果 main
退出,GopherJS 不会关闭所有内容并退出(部分原因是:这究竟意味着什么?最接近 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 调用的函数中执行此操作,因此它会出现恐慌。 (当我在 playground 中 运行 时,我也得到 Uncaught TypeError: r is not a function
,但这只是早期错误的后果。)
我 认为 你想做的是等待 doRequest
完成,打印值,然后 return,但这是行不通的。为此,您需要使用本机 Javascript 承诺或其他一些异步机制。
为什么下面的代码会出现死锁?我正在尝试 return 从 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]:
.....
func main() {
c := make(chan bool)
js.Global().Set("test", js.FuncOf(test))
<-c
}
您已经创建了一个通道 c
,然后等待从中接收值。请注意 c
是 main
函数的局部变量。对 c
的引用永远不会在程序中的任何其他地方传递,因此 c
通道上永远不会发送值,因此您的主 goroutine 将永远等待接收。
与错误消息中的内容差不多。所有的协程都在睡觉。 main
不启动任何东西,只是接收一个通道,所以它被阻塞了,并且没有其他 goroutines 运行ning,所以 main
不可能再次醒来,所以运行时间恐慌。
如果我没记错的话,与常规 Go 不同,如果 main
退出,GopherJS 不会关闭所有内容并退出(部分原因是:这究竟意味着什么?最接近 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 调用的函数中执行此操作,因此它会出现恐慌。 (当我在 playground 中 运行 时,我也得到 Uncaught TypeError: r is not a function
,但这只是早期错误的后果。)
我 认为 你想做的是等待 doRequest
完成,打印值,然后 return,但这是行不通的。为此,您需要使用本机 Javascript 承诺或其他一些异步机制。