读写分离

Go 在往 chan 里写数据的时候, 是没有办法判断该 chan 是否是关闭的, 此时必须要加上一个标志位, 在发送之前判断一下
正常情况下是可行的, 但是在压测的时候还是会出现往一个已经关闭的 chann 写数据 panic 的情况
于是想过几种方法

将标志位的判断和发送语句放在一起, 尽量缩短两句执行的时间差, 代码如下

if this.isClosed == true {
    return
}
msg <- data

测试的时候没有出现 panic 的概率会变小, 但还是会有出现的情况, 猜想可知多核的情况下 msg 还是可能在两条语句中间被关闭掉

我想到的最好的方法就是 msg 不能再其他 goroutine 被关闭, 只和发送数据的函数在同一个 goroutine, 代码如下

select {
case <-this.ExitChan:
    close(this.msgChan)
    return nil 
case this.msgChan <- msg:
} 

日志问题

由于日志会在在并发的情况下写文件,想达到顺序写入必然涉及到加锁
自己的日志需要加一些额外的信息,所以不会直接调用 log 库
在上层需要封装一些信息,也要加锁,于是把 log 库的内容取出来,重新封装一下 这样就不用加两次锁

goroutine 泄漏

func runTask(id int) string {
    time.Sleep(10 * time.Millisecond)
    return fmt.Sprintf("The result is from %d", id) 
}

func FirstRsp() string {
    num := 10
    ch := make(chan string)
    for i := 0; i < num; i++ {
        go func(i int) {
            ret := runTask(i)
            ch <- ret 
        }(i)
    }   
    return <-ch
}

func TestFirstrsp(t *testing.T) {
    t.Log("before:", runtime.NumGoroutine())
    t.Log(FirstRsp())
    time.Sleep(time.Second)
    t.Log("after:", runtime.NumGoroutine())
}

此处FirstRsp 接收到 ch 的值之后就返回,有9个goroutine 会阻塞在 ch 的发送上,造成泄漏
如果将 ch 改成 buff chan 就可以解决泄漏的问题

连接的关闭,chan 的关闭,客户端主动关闭,服务器心跳超时关闭,服务器主动关闭,都会有重复关闭一个已经关闭的 chan,设计比较头疼