请教个select...case...问题,烦恼了好几天了

orthocore 2020-10-20 10:55:15
共有两台服务器A跟B,它们使用一条grpc长链接进行交互,A是grpc服务端,在公网;B是客户端,在内网。 服务器A的代码里有两个协程,分别监听http和grpc,用一个同步channel进行通信。

我的业务流程: 1、用户通过http接口访问A,A需要调用B的程序,此时使用Send(*Response) error把必要的参数发送过去; 2、B通过Recv()监听到A发来的请示,把运算结果通过Send()发送回A; 3、A通过Recv()收到运算结果,把结果输入到同步channel,http服务结束同步阻塞,返回http response给用户。

现在我要在步骤1加上30秒超时的限制,却出现了奇怪的问题,伪代码如下:


A.Send("data...")

go func() {
time.Sleep(30e9)
timeoutChan <- true
}()

select {
case <-timeoutChan:
// 返回超时错误信息
case resp := <-respChan:
// 正常返回数据
}


按照我的想法,应该是用户访问A的http接口时,如果超过30秒,会得到个超时错误。但却产生以下问题,有并发请示时(假设恰好请示1和请示2),请示1得到的http response是请示2的运算结果,请示2得到的http response是请示1的运算结果。

我回滚到原代码,(即去掉了超时限制功能,没有上边的go func(){time.Sleep()}和select... case...),只使用同步channel一直阻塞等待返回结果,进行压力测试,并不会出上以上问题,http request跟response都能对应。所以现在想不通,为何select... case...会出现以上问题,我需要做什么改进。
...全文
148 2 打赏 收藏 转发到动态 举报
写回复
用AI写文章
2 条回复
切换为时间正序
请发表友善的回复…
发表回复
qybao 2020-10-21
  • 打赏
  • 举报
回复
你的chanel是全局变量还是局部变量?多线程共享变量要注意同步。 你的代码不全,推测是这些chanel都是共享变量,请求1和请求2主线程都在select阻塞,但是respChan是共享的,请求1处理的協程结束后往respChan通道发送结果,被请求2在select先抢到了,结果请求2就返回了请求1的response,同样,请求2处理的協程结束后往respChan通道发送结果,被请求1抢到了,结果请求1就返回了请求2的response。说白了就是多线程处理,rrspChan共享变量的同步没做好。
orthocore 2021-10-11
  • 举报
回复
@qybao 当时看了你的答案就去翻代码了,的确是这问题。谢了!!当时太忙忘记答谢。

2,190

社区成员

发帖
与我相关
我的任务
社区描述
go语言学习与交流版
社区管理员
  • go语言社区
  • Freeman Z
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧