nats.dos

1.connect的时候开启一个goroute, 通过channel的来进行flush.
2. subscribe的时候开启goroute处理事件
3. 接收消息后解开msg-chain然后signal[2]中的goroute, 可以不停的往msg-chain上挂新的消息.

以下是细节分析:

  1. 当我们频繁使用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
}
  1. 通过链表来进行对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()
   }

}

原文:
https://www.oreilly.com/ideas/scaling-messaging-in-go-network-clients?intcmp=il-prog-na-article-na_new_site_building_messaging_in_go_network_clients

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值