使用GopherJS在goroutine中陷入僵局

问题描述 投票:0回答:2

为什么下面的代码中出现死锁?我正在尝试从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]:
.....
go deadlock gopherjs
2个回答
0
投票
func main() {
    c := make(chan bool)
    js.Global().Set("test", js.FuncOf(test))
    <-c
}

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


0
投票

几乎是错误消息中所说的。所有goroutine都在睡觉。 main不会启动任何东西,只接收一个通道,因此它被阻塞,并且没有其他goroutine正在运行,因此main不可能再次唤醒,因此运行时会出现紧急情况。

[如果我没记错的话,不像普通的Go,GopherJS不会关闭所有内容并在main退出时退出(部分原因是:那到底意味着什么?与Go程序最接近的类比是关闭网页!太烂了,所以GopherJS不会那样做。因此,严格来说,在GopherJS中,您不必为使main保持活动状态而进行的操作。

就是说,如果您在最后说(例如)time.Sleep(time.Hour),则在所有goroutine仍处于睡眠状态(严格来说)时,main最终会唤醒,运行时知道,所以它不会在这种情况下恐慌。

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

© www.soinside.com 2019 - 2024. All rights reserved.