我用的是 echo 里面的 gorilla websocket 示例
https://echo.labstack.com/cookbook/websocket
我原本的后台是 node 写的,node 上没事,但是为什么 go 这边是按顺序执行的而不是同时执行?
这是用node写的,是可以同时执行的
var conn *websocket.Conn
func (c *Controller) Subscribe(ctx echo.Context) error {
upgrader := websocket.Upgrader{
CheckOrigin: func(r *http.Request) bool {
return true
},
EnableCompression: true,
}
ws, err := upgrader.Upgrade(ctx.Response(), ctx.Request(), nil)
if err != nil {
return err
}
conn = ws
go c.readLoop(ctx)
return nil
}
func (c *Controller) readLoops(ctx echo.Context) {
token := ctx.Request().URL.Query().Get("auth")
userData, err := c.userService.GetUserDataFromCache(token)
if err != nil {
_ = conn.WriteJSON(tool.WebsocketResponse("error", err.Error(), nil))
}
for {
body := new(socketRequest)
if err := conn.ReadJSON(body); err != nil {
_ = conn.WriteJSON(tool.WebsocketResponse("error", err.Error(), nil))
}
if err := ctx.Validate(body); err != nil {
_ = conn.WriteJSON(tool.WebsocketResponse("error", err.Error(), nil))
} else {
switch body.Event {
case "create":
albumId, err := c.hashId.HashIdDecode(*body.Payload.AlbumId)
if err != nil {
_ = conn.WriteJSON(tool.WebsocketResponse("error", err.Error(), nil))
}
if event, err := c.CreateFromUrl(userData.Id, albumId, *body.Payload.Url); err != nil {
_ = conn.WriteJSON(tool.WebsocketResponse(event, err.Error(), body.Payload))
} else {
_ = conn.WriteJSON(tool.WebsocketResponse(event, "", body.Payload))
}
}
}
}
}
解决咯~
在for里面写个go func,这样每次收到event的时候就能去开启一个goroutine去执行任务咯~ 这样写只是我一个人用而已没加消息队列。如果是大站的话不加估计会挂掉~
1
knva 2020-07-10 14:51:05 +08:00
没做过,但是我觉得开个协程不就得了
|
2
binux 2020-07-10 14:56:37 +08:00 via Android
执行什么?
|
3
w99w 2020-07-10 14:59:41 +08:00
你的请求是同时嘛?
|
4
wunonglin OP @binux #2 执行了个 http 请求,我页面是 6 个任务同时发送的,但是后台是一个接一个执行,而不是同时执行 6 个任务
|
6
takemeaway 2020-07-10 15:02:04 +08:00
如果没有开协程和多线程,那么本身就是按顺序执行的。
|
7
wunonglin OP @takemeaway #6 对,我是想过应该是这个问题。刚接触 go 还不太了解,没搜到有关 websocket 的教程或者例子,找到的那些都是聊天室的例子,但我这个只是 1v1 的
|
8
BingoXuan 2020-07-10 15:15:46 +08:00
因为你函数写的是同步代码,你需要开协程去处理,并通过 chan 来收发结果。
起码把代码发一下,不然 v 友都不知道你做了什么暗箱操作 |
9
whileFalse 2020-07-10 15:24:00 +08:00
LZ 的 Node 环境是不是开了多线程了。
Node 本身是异步单线程的,加上多线程那就是乱序了…… |
11
wunonglin OP @whileFalse #9 单线,异步的。转 go 之后不知道 go 这边要怎么写
|
12
keepeye 2020-07-10 15:30:48 +08:00
第一张图每次 send 间隔好几毫秒啊 同时请求??
|
13
wunonglin OP @keepeye #12
也不能说死磕”同时“这个字眼,你发到后台去,按我理解的话它肯定是接收到一个就去执行一个,但是 go 这边像是被缓存住了,是一个执行完成后再去执行,而不是“接收到一个就去执行一个”。应该就是像#6 说的那样 |
14
keepeye 2020-07-10 15:43:54 +08:00
@wunonglin 一个长连接本来就是顺序接收消息的啊,不知道 node 是怎么处理的,可能收到一条消息都生成 async task 类似 goroutine 吧
|
15
xylophone21 2020-07-10 15:44:04 +08:00
1. 看一下你给的链接里的 demo,https://github.com/labstack/echox/blob/master/cookbook/websocket/gorilla/server.go 。Subscribe 里 readLoop 不应该新开 go 程,直接卡在这里,直到 ws 断开。因为 Subscribe 是 HTTP Server 调的,你返回了,它就会认为这个连接已经结束了,虽然不一定会马上关(keep-alive),但必要的时候会断开。
2. 作为一个 HTTP Server,Subscribe 应该是在不同的 go 程里被调用的,不然就就成了单协程了,你可以打印出来试一下 |
17
wunonglin OP @xylophone21 #15
上面 append 的是我测试的代码,在跑着的代码是这样的 https://play.golang.org/p/4_Y4wUE3iNy,跟例子一样的,然后东搞搞西搞搞就成了上面那样 |
18
xylophone21 2020-07-10 16:11:37 +08:00
|
19
keepeye 2020-07-10 16:12:29 +08:00
@wunonglin nestjs 里面改成同步响应就和 go 一样了,或者 go 里面读到 body 的时候新建一个 goroutine 处理这样也就和 nestjs 里的异步响应效果一样。你用 nodejs 之所以习惯了异步处理是因为程序是单线程的,同步可能会长时间阻塞其他的请求,但在 go 里面,每个连接本身就在一个 goroutine 里,放心用同步的方式处理消息就是了,还能避免乱序问题
|
22
BingoXuan 2020-07-10 16:40:09 +08:00
@wunonglin
我觉得你不要开协程去做 readloop,直接执行 readloop 。如果 CreateFromUrl 方法中涉及 io 处理或者可以并发执行的话,可以开协程执行并通过 chan 取回结果。参考: http://litang.me/post/golang-channel/#%E5%A4%9A%E5%86%99%E4%B8%80%E8%AF%BB |
23
wunonglin OP |
25
Fitz 2020-07-10 19:48:37 +08:00
看到最后才看懂楼主的顺序执行是什么意思......同一个连接里收到的 event, 那可不就是顺序执行, 想要并发就在 for 循环里只要 ReadMessage 读到数据, 就启个 goroutine 去处理, 你 go c.readLoop(ctx)用错地方了.
|
30
hantsy 2020-07-11 15:56:05 +08:00
@wunonglin 最近玩了一下 Nestjs,如果没有 Rxjs 支持, 我根本就没兴趣。
Nestjs 很多概念很源自 Angular,写 Angular 习惯了,async,await 和 promise 那一套实在用起来难受。Nestjs 内部几乎和 Angular 一致,都是 Rxjs 优先,但可惜,第三方集成很多还是基于 Promise 。 https://github.com/hantsy/nestjs-sample 我这个的 Sample 除了 LocalStrategy 用了 Promise (用 Observable,需要额外转换),其它地方都是 Rxjs 。 |