duanjiati1755 2019-09-07 17:28
浏览 249

syscall / js websocket回调在非阻塞行为中不响应

I have two processes running, written in Go in which one (sender.go) sends a message to another (listener.go) while being stuck in a for loop via websockets.

The issue is that listener.go only realizes it received the message after it terminates the loop.

I have tried several websocket libraries, I even tried using regular tcp streams, but it won't work when compiled in webassembly because browser won't support it. The syscall/js websocket seemed to be the perfect fit despite this behaviour.

here's listener.go

func registerCallbacks(ws js.Value) {
    ws.Call("addEventListener", "message", js.FuncOf(func(this js.Value, args []js.Value) interface{} {
        message := args[0].Get("data").String()
        fmt.Println("message received ")
        fmt.Println(message)
        return nil
    }))
}


func main() {
    c := make(chan struct{}, 0)
    toIP := "127.0.0.1"
    toPort := 8081
    ws := js.Global().Get("WebSocket").New(fmt.Sprintf("ws://%s:%d/ws", toIP, toPort))
    registerCallbacks(ws)
    const bigNum uint64 = 100000 * 10000
    cb := func(this js.Value, args []js.Value) interface{} {
      for i := uint64(0); i < bigNum; i++ {
        doThings()
        if i%10000000 == 0 {
            fmt.Println("skimmed ten millions ")
        }
      }
      fmt.Println("Exited for loop !!")
      return nil
    }
    // call cb() in script of index.html from a button
    js.Global().Set("cb", js.FuncOf(cb))
    <-c
}

So is sender.go,

func main() {
    toIP := "127.0.0.1"
    toPort := 8081
    ws := js.Global().Get("WebSocket").New(fmt.Sprintf("ws://%s:%d/ws", toIP, toPort))
    time.Sleep(1 * time.Second)
    fmt.Println("sending  ")
    ws.Call("send", js.ValueOf("msg"))
    fmt.Println("Program exit  ")
}

If someone's willing to reproduce the issue here's the websocket server which receives message from sender to forward it to receiver, written in node.js, just copy and paste this, it works fine with several projects

const port = 8081;
const host = '127.0.0.1';

var WebSocketServer = require('websocket').server;
var http = require('http');

var server = http.createServer(function(request, response) {});

server.listen(port, host, () => {
    console.log('WS Server is running on port ' + port + '.');
});

wsServer = new WebSocketServer({
    httpServer: server
});

let sockets = [];


wsServer.on('request', function(request) {
  var connection = request.accept(null, request.origin);
  sockets.push(connection)
  console.log("Connection with node initiated")
  connection.on('message', function(message) {
    console.log("message received "+message)
    sockets.forEach(function(s, index, array) {
      if (message.type === 'utf8') {
        broadcastData = message.utf8Data
        console.log("message is: "+ broadcastData)
        if(s!= connection) {
          console.log('send data to ' + s.socket.remotePort + ': ' + broadcastData);
          s.sendUTF(broadcastData)
        }
      }
    });
  });
});

I am expecting listener.go to receive message before it exits the for loop

PS: Using sleep statement is not a good help , because when this for loop runs inside a js callback, the sleep statement outputs a panic.

  • 写回答

1条回答 默认 最新

  • dragon8997474 2019-09-07 21:05
    关注

    First, note that if you are generating wasm Go code, it's not multi-threaded, at least not today (September 2019). See How to implement multithreading in wasm created using golang? So there's only one actual execution thread.

    Then, remember that goroutines are cooperatively multi-tasked onto whatever threads are available. Since there's only one thread, there's only one goroutine running at any time. If your running goroutine does not give up the processor to other goroutines, those other goroutines won't run.

    You can give up the processor implicitly—for instance, by waiting on a channel or a mutex—or explictly, via time.Sleep or runtime.Gosched. Without such a call, any goroutine that would notice the incoming message never gets a chance to see it, and your callback—which will run in this or some third goroutine—never gets called.

    (If you run natively, rather than in wasm, you will generally get more threads and will be able to have other CPUs run other tasks even while one is in a tight loop.)

    评论

报告相同问题?

悬赏问题

  • ¥50 有数据,怎么建立模型求影响全要素生产率的因素
  • ¥50 有数据,怎么用matlab求全要素生产率
  • ¥15 TI的insta-spin例程
  • ¥15 完成下列问题完成下列问题
  • ¥15 C#算法问题, 不知道怎么处理这个数据的转换
  • ¥15 YoloV5 第三方库的版本对照问题
  • ¥15 请完成下列相关问题!
  • ¥15 drone 推送镜像时候 purge: true 推送完毕后没有删除对应的镜像,手动拷贝到服务器执行结果正确在样才能让指令自动执行成功删除对应镜像,如何解决?
  • ¥15 求daily translation(DT)偏差订正方法的代码
  • ¥15 js调用html页面需要隐藏某个按钮