1.connect的时候开启一个goroute, 通过channel的来进行flush.
2. subscribe的时候开启goroute处理事件
3. 接收消息后解开msg-chain然后signal[2]中的goroute, 可以不停的往msg-chain上挂新的消息.
以下是细节分析:
- 当我们频繁使用Flush会降低速度.
文中给出的答案是通过一个channel来控制是否做flush.
func (c*Client)Connect(uri string)error{
//...省略
c.fch = make(chan struct{}, 1024)
go func(){
for _:= range c.fch {
c.Lock()
if c.w.Buffered() > 0 {
c.w.Flush()
}
c.Unlock()
}
}()
}
还有一种写法是:
func (c*Client)Connect(uri string)error{
//...省略
c.fch = make(chan struct{}, 1024)
go func(){
for{
if _, ok:=<-c.fch; !ok{
return
}
c.Lock()
if c.w.Buffered() > 0 {
c.w.Flush()
}
c.Unlock()
}
}()
}
publish的时候就可以根据channel的状态进行kick off:
func (c*Client)Publish(subject string, payload[]byte)error{
//...省略
if nil == err{
// 重点:
if len(c.fch) == 0 {
select{
case c.fch <- struct{}{}:
default:
}
}
}
c.Unlock()
return err
}
- 通过链表来进行对subscribed消息的callback
func (c*Client)processMsg(subject string, reply string, sid int, payload[]byte){
//注意, 从map读写都要加锁. (也许下一步的改进是采用读写锁)
c.Lock()
subt, ok := c.cbs[sid]
c.Unlock()
if ok {
// 插入消息队列.
subt.mu.Lock()
if subt.pHead == nil {
subt.pHead = msg
subt.pTail = msg
} else {
subt.pTail.next = msg
subt.pTail = msg
}
subt.pCond.Signal() // 唤醒另一个routine
subt.mu.Unlock()
}
}