2013-06-24 41 views
10

我需要定期刷新頻道的內容。 我用len()做了這個,我想知道是否有更好的方法來做到這一點。golang中定期刷新頻道

http://play.golang.org/p/YzaI_2c_-F

package main 

import (
    "fmt" 
    "math/rand" 
    "time" 
) 

func main() { 
    commch := make(chan int, 100) 
    go fillchan(commch) 
    drainchan(commch) 
} 

func fillchan(commch chan int) { 
    for { 
     select { 
     case <-time.Tick(30 * time.Millisecond): 
      commch <- rand.Int() 
     } 
    } 
} 

func drainchan(commch chan int) { 
    for { 
     chanlen := len(commch) // get number of entries in channel 
     time.Sleep(1 * time.Second) 
     for i := 0; i <= chanlen; i++ { //flush them based on chanlen 
      fmt.Printf("chan len: %s num: %s\n", chanlen, <-commch) 
     } 
    } 
} 

EDIT 1:看起來這是更好的方式來做到這一點 http://play.golang.org/p/4Kp8VwO4yl

package main 

import (
    "fmt" 
    "math/rand" 
    "time" 
) 

func main() { 
    commch := make(chan int, 1000) 
    go fillchan(commch) 
    for { 
     select { 
     case <-time.Tick(1000 * time.Millisecond): 
      drainchan(commch) 
     } 
    } 
} 

func fillchan(commch chan int) { 
    for { 
     select { 
     case <-time.Tick(300 * time.Millisecond): 
      commch <- rand.Int() 
     } 
    } 
} 

func drainchan(commch chan int) { 
    for { 
     select { 
     case e := <-commch: 
      fmt.Printf("%s\n",e) 
     default: 
      return 
     } 
    } 
} 

編輯2:去除選擇,防止內存泄漏time.Tick http://play.golang.org/p/WybAhRE3u4

package main 

import (
    "fmt" 
    "math/rand" 
    "time" 
) 

func main() { 
    commch := make(chan int, 1000) 
    go fillchan(commch) 
    for _ = range time.Tick(1000 * time.Millisecond) { 
     drainchan(commch) 
    } 
} 

func fillchan(commch chan int) { 
    for _ = range time.Tick(300 * time.Millisecond) { 
     commch <- rand.Int() 
    } 
} 

func drainchan(commch chan int) { 
    for { 
     select { 
     case e := <-commch: 
      fmt.Printf("%s\n", e) 
     default: 
      return 
     } 
    } 
} 
+5

該代碼是一個大的競爭條件。 – cthom06

+3

爲什麼要刷新頻道的內容?你想解決什麼問題? – peterSO

+2

如果你想等待陳,你最好使用'select {case <-commch:...' – mattn

回答

6

需要清除頻道的內容將是不尋常的。頻道不提供這種功能 - 但你可以做一個goroutine這樣做(...如果你真的確實想要)。

通常情況下,你會考慮更多關於一個通道的輸入和另一個通道的輸出;兩個通道都攜帶相同的數據類型。原則上,您可以用這種方式對所有緩衝通道進行建模;對其客戶來說,goroutine的行爲就像一個普通的緩衝渠道,因爲它傳遞了它接收到的信息。

將第三個通道添加到goroutine中,並結合選擇它與輸入之間的。這將允許您在沒有競態條件的情況下觸發清空緩衝區。簡單。

現在有三個通道連接到goroutine - 兩個輸入和一個輸出。所以,當你設計將使用它的東西時,你可以推斷清除數據的語義。

一個相對的心靈。考慮有一個輸入和一個輸出通道的goroutine。它提供了一個固定大小的覆蓋緩衝區,即一個即使在輸出通道被阻塞的情況下也能隨時從其輸入通道讀取的覆蓋緩衝區。這也將需要一個選擇與默認情況下,但不需要第三個通道。覆蓋緩衝區有一個明確的用例:當通道和goroutines連接成循環時,死鎖很可能發生。覆蓋緩衝區可以作爲一個候選解決方案用於解決死鎖問題,因爲一些數據在遲到時無用 - 例如,當應用程序忙於響應它們時,例如,您可以在GUI中丟棄鼠標事件。

+0

我明白你要去哪裏。我認爲維持排水目的的互斥可能更合適。 –

+0

不,完全相反。 CSP過程的要點是其內部狀態依次改變*(因此名稱)。在goroutines內部不存在不共享外部狀態的競爭條件。所以在這種情況下從不需要互斥體。 –