如何明确清空频道?

时间:2014-10-01 13:54:41

标签: go channels

简短版本: 有没有办法清空go通道而不重新创建它,或者循环通过它?

原因: 我正在使用两个通道来发送和接收数据,我还有一个额外的通道来表示需要重新连接。

现在,当传输重置/重新连接时,我想“清空”额外的通道,以确保没有任何延迟的其他重置请求会导致该事件再次重新连接。

4 个答案:

答案 0 :(得分:17)

没有循环就无法清空通道。如果你没有任何并发​​接收器,那么你可以使用这个简单的循环:

for len(ch) > 0 {
  <-ch
}

如果你有并发接收器,那么使用循环:

L:
for {
    select {
    case <-c:
    default:
       break L
    }
}

答案 1 :(得分:2)

您所描述的内容本质上是活泼的,因为可能有合法的请求在频道上重新连接。我建议跟踪时间,而不是试图消耗频道。

在重新连接频道上,发布时间。完成重新连接后,请记下时间。在使用重新连接通道时,请丢弃任何早于上次重新连接的消息。

另一个实现此目标的锁步解决方案是使重新连接通道成为一个bool。发布“true”以重新连接。重新连接完成后,发布“false”。然后使用频道直到找到“false”。

答案 2 :(得分:2)

另一种方法是使用sync.Condatomic,类似于:

type Server struct {
    s     chan int
    r     chan int
    c     *sync.Cond
    state uint32
}

const (
    sNormal       = 0
    sQuitting     = 1
    sReconnecting = 2
)

func New() *Server {
    s := &Server{
        s: make(chan int),
        r: make(chan int),
        c: sync.NewCond(&sync.Mutex{}),
    }
    go s.sender()
    // go s.receiver()
    return s
}
func (s *Server) sender() {
    //
    for {
        select {
        case data := <-s.s:
        //do stuff with data
        default:
            s.c.L.Lock()
        L:
            for {
                switch atomic.LoadUint32(&s.state) {
                case sNormal:
                    break L
                case sReconnecting:
                case sQuitting:
                    s.c.L.Unlock()
                    return
                }
                s.c.Wait()
            }
            s.c.L.Unlock()
        }
    }
}

//repeat for receiver

func (s *Server) Reconnect() {
    var cannotReconnect bool
    atomic.StoreUint32(&s.state, sReconnecting)
    //keep trying to reconnect
    if cannotReconnect {
        atomic.StoreUint32(&s.state, sQuitting)
    } else {
        atomic.StoreUint32(&s.state, sNormal)
    }
    s.c.Broadcast()
}

playground

答案 3 :(得分:0)

这听起来像是重置通道而不是重置goroutine。它将从发送复位信号的一侧输入,并向接收器输出。当此goroutine收到重新连接请求时,它会将其传递给接收方。然后它等待在第三个通道上接收来自接收器的确认,同时丢弃它收到的任何重新连接请求。所以总共3个通道,1个输入,1个输出,1个确认。