猿问

定期刷新 golang 中的通道

我需要定期刷新频道的内容。我用 len() 做到了这一点,我想知道是否有更好的方法来做到这一点。


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)

        }

    }

}

编辑 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:删除选择,防止内存泄漏随着时间的推移。滴答 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

        }

    }

}


千巷猫影
浏览 147回答 3
3回答

冉冉说

需要清除频道的内容是不寻常的。频道不提供此功能 - 但您可以制作一个以这种方式运行的 goroutine(...如果您真的想要的话)。通常,您会更多地考虑在一个通道上输入并在另一个通道上输出的 goroutine;两个通道都携带相同的数据类型。原则上,您可以通过这种方式对所有缓冲通道进行建模;对于它的客户端,goroutine 的行为就像一个普通的缓冲通道,因为它传递它接收到的内容。将第三个通道添加到 goroutine 中,并在它和输入之间进行选择。这将允许您触发缓冲区的清空,而不会出现竞争条件。简单。现在有三个通道连接到 goroutine - 两个输入和一个输出。因此,当您设计将使用它的事物时,您可以推断刷新该数据的语义是什么。一个亲戚浮现在脑海中。考虑一个具有一个输入和一个输出通道的 goroutine。它提供了一个固定大小的覆盖缓冲区,即一个总是准备好从其输入通道读取的缓冲区,即使输出通道被阻塞。这也需要一个默认情况下的选择,但不需要第三个通道。覆盖缓冲区有一个明确的用例:当通道和 goroutine 连接到循环中时,很可能发生死锁。覆盖缓冲区作为死锁的一种候选解决方案派上用场,因为有些数据在迟到时是无用的——例如,当应用程序太忙而无法响应它们时,您可以在 GUI 中丢弃鼠标事件。

阿晨1998

当我遇到这个问题时,我就是这样处理的。func (s *ReadStream) drain() {&nbsp; &nbsp; go func() {&nbsp; &nbsp; &nbsp; &nbsp; for b := range s.chan {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; blackhole(b)&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }()}func blackhole(b []byte) {}在您的选择可能被阻止的情况下 context.Context 似乎是错误的选择:for {&nbsp; &nbsp; select {&nbsp; &nbsp; case <-ctx.Done():&nbsp; &nbsp; &nbsp; &nbsp; return&nbsp; &nbsp; default:&nbsp; &nbsp; &nbsp; &nbsp; send<-getData()&nbsp; &nbsp; }}如果发送已满,则在接收完成信号之前,我们会受到外部 goroutine 的支配。如果您确定消费者会在通道关闭之前阅读,这是可以的,但是如果这些消费者可能会遇到错误情况并返回,那么您所能做的就是希望。在这种特定情况下,我喜欢用内部退出 chan 和等待组替换上下文,然后提供公共 Kill() 方法。当然,只要我绝对确定我可以扔掉数据。func (s *ReadStream) Kill() {&nbsp; &nbsp; s.quit<-struct{}{}&nbsp; &nbsp; s.drain()&nbsp; &nbsp;// ensure goroutine sees the cancel&nbsp; &nbsp; s.wg.Wait() // wait for goroutine to see the cancel&nbsp; &nbsp; s.close()}
随时随地看视频慕课网APP

相关分类

Go
我要回答