2014-10-01 20 views
4

簡短版本: 有沒有辦法在不重建或循環播放頻道的情況下清空頻道?如何明確清空頻道?

原因: 我使用兩個通道來發送和接收數據,並且我有一個額外的通道來指示需要重新連接。

現在,當傳輸已被重置/重新連接時,我想'清空'額外的通道,以確保沒有任何其他重置請求會導致重新連接。

+0

的[在golang週期性沖洗通道]可能重複(http://stackoverflow.com/questions/ 17284349 /週期性沖洗通道在golang) – Floegipoky 2014-10-01 14:07:30

+0

你可以更具體的關於你的用例嗎?具體說明你正在重新連接到什麼以及爲什麼。沒有所有細節,我覺得真正需要解決的問題是將垃圾數據放入您的頻道,而不是事後刪除它。 – Floegipoky 2014-10-01 14:12:26

+0

@Floegipoky:這兩個通道是通過套接字發送和接收數據的,在處理協議的代碼的不同部分分析數據。如果協議發現錯誤,我希望能夠通知傳輸層需要重新連接。這就是爲什麼我需要額外的頻道 – Toad 2014-10-01 14:29:21

回答

2

你所描述的是什麼本質上是活潑的,因爲可能有合法的請求重新連接到該頻道。我不會試圖消耗渠道,我會建議跟蹤時間。

在您的重新連接頻道上,張貼時間。完成重新連接後,記下時間。在使用重新連接通道時,丟棄比上次重新連接更早的任​​何消息。

另一個解決方案是使重新連接通道成爲布爾。發佈「true」重新連接。重新連接完成後,發佈「false」。然後消耗頻道,直到您發現「錯誤」。

+0

我喜歡時間戳方法。它仍然通過頻道循環,但在這種情況下,你是對的,至少我不能意外刪除任何新的請求 – Toad 2014-10-01 14:26:29

7

無法清空沒有循環的通道是不可能的。如果你沒有任何併發​​的接收器,那麼你可以使用這個簡單的循環:

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

如果你有併發的接收器,然後使用循環:

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

我認爲這樣做的風險在於,如果其他人也在閱讀該頻道,可能會阻止。 (在我的情況下,沒有額外的讀者,但它是值得注意的警告) – Toad 2014-10-01 14:27:42

+0

啊,你是對的。我錯過了。 – Toad 2014-10-01 14:31:25

0

聽起來好像不是重置通道,而是想要重置goroutine。它將從發送重置信號的一側輸入,並將輸出發送到接收器。當此goroutine收到重新連接的請求時,會將其傳遞給接收方。然後,它等待在第三個通道上收到來自接收器的確認,同時丟棄它收到的任何重新連接請求。所以共有3個通道,1個輸入,1個輸出,1個確認。

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

+0

這些鎖是否會對性能不利? – Toad 2014-10-08 10:42:20

+0

@Toad是的,但你並沒有太多的選擇,在處理併發時,你必須使用某種鎖定/原子機制。這是我能想到的唯一方法,無需添加像Floegipoky建議的額外頻道。此外,渠道使用自己的鎖,所以你不會得到太多的東西。 – OneOfOne 2014-10-08 10:46:07