golang 信道的坑

今天遇到一个问题,功能很简单,就是给线上的文章加锁,每篇文章只能由一个人访问编辑,设想很简单,两个结构体,一个结构体 hub 保存全部的正在被访问的文章的列表,一个结构体 client 是文章的内容以及属性。当每个文章被访问的时候,将放入信道hub的一个信道之中,单独开一个goroutine , 监听goroutine的信号变化,一旦信道变化,就读取变化,然后放入数组中。

很简单,对吧。但就是出了奇葩问题。

我开始的时候,准备两个函数,一个Index,处理http/websocket请求,一个是监听hub信道变化的,在Index 函数里面,通过信道将正在访问的文章信息传递给hub,然后我发现了灵异的情况,就是及时赋值给信道,也是没有用处的,必须等这个链接短开之后,被监听到,但是这个时候,链接已经断开了,文章已经不被访问了。

解决方法是写三个函数,一个是监听hub信道变化的,一个是原来的Index,然后把阻塞监听websocket 链接的部分放在一个新的函数里面,然后将对hub信道变化的部分放在Index里面,这样,等Index函数执行完毕的时候,Hub就能捕捉到信道变化了。

Here is the code

func Index(w http.ResponseWriter, r *http.Request) {

…….

  h.register <- c                                                                                                                                                           

       for {

       //守护着这个连接,从连接中读取信息,然后通过信道传递给broadcast ,进入传递的队列

         _, msg, err := c.ws.ReadMessage()

         if err != nil {

             break

         }

         h.broadcast <- string(msg)

       }

      defer func() {

       Println(“defering”)

       h.unregister <- c

       c.ws.Close()

        close(c.send)

}()

}

新的方案就是把除第一行以外的代码,从for开始,到close下面的独立出来,放在一个新的函数里面,然后调用这个函数,h.register <- c 保留在Index函数里,这样在调用新函数的时候,监听h.register的函数就能捕捉到register的变化了

/****************************************************************************************/

经朋友指点,指出是缓冲的问题,register变量声明的时候,是通过make(chan *client)的方式,这样声明会默认自己带缓冲,所以可以通过make(chan *client,1)的方式,这样赋值之后,立即生效,检测register变化的函数立即就捕捉到了信道的变化,

Leave a comment

Your email address will not be published.

*