本文介绍了在时间间隔和通道长度之间进行选择的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧! 问题描述 任务: 将频道中的数据写入文件。 问题: 我有一个频道 ch:= make(chan int,100) I需要从通道读取并将从通道读取的值写入文件。我的问题基本上是这样做的 如果频道 ch 是如果频道 ch 未满,请每隔5秒写一次。 因此,基本上,数据需要至少每5秒写入一次文件(假设数据至少会填充到通道中每5秒) 使用选择,用于 谢谢! 范围 div class =h2_lin>解决方案 没有像缓冲区的通道已满这样的事件,因此您无法检测到[*]。这意味着你不能通过只使用1个通道的语言原语来习惯性地解决你的问题。 I would use another channel from which I would receive as values are sent on it, and "redirect", store the values in another channel which has a buffer of 100 as you mentioned. At each redirection you may check if the internal channel's buffer is full, and if so, do an immediate write. If not, continue to monitor the "incoming" channel and a timer channel with a select statement, and if the timer fires, do a "regular" write.You may use len(chInternal) to check how many elements are in the chInternal channel, and cap(chInternal) to check its capacity. Note that this is "safe" as we are the only goroutine handling the chInternal channel. If there would be multiple goroutines, value returned by len(chInternal) could be outdated by the time we use it to something (e.g. comparing it).In this solution chInternal (as its name says) is for internal use only. Others should only send values on ch. Note that ch may or may not be a buffered channel, solution works in both cases. However, you may improve efficiency if you also give some buffer to ch (so chances that senders get blocked will be lower).var ( chInternal = make(chan int, 100) ch = make(chan int) // You may (should) make this a buffered channel too)func main() { delay := time.Second * 5 timer := time.NewTimer(delay) for { select { case v := <-ch: chInternal <- v if len(chInternal) == cap(chInternal) { doWrite() // Buffer is full, we need to write immediately timer.Reset(delay) } case <-timer.C: doWrite() // "Regular" write: 5 seconds have passed since last write timer.Reset(delay) } }}If an immediate write happens (due to a "buffer full" situation), this solution will time the next "regular" write 5 seconds after this. If you don't want this and you want the 5-second regular writes be independent from the immediate writes, simply do not reset the timer following the immediate write.An implementation of doWrite() may be as follows:var f *os.File // Make sure to open file for writingfunc doWrite() { for { select { case v := <-chInternal: fmt.Fprintf(f, "%d ", v) // Write v to the file default: // Stop when no more values in chInternal return } }}We can't use for ... range as that only returns when the channel is closed, but our chInternal channel is not closed. So we use a select with a default case so when no more values are in the buffer of chInternal, we return.ImprovementsUsing a slice instead of 2nd channelSince the chInternal channel is only used by us, and only on a single goroutine, we may also choose to use a single []int slice instead of a channel (reading/writing a slice is much faster than a channel).Showing only the different / changed parts, it could look something like this:var ( buf = make([]int, 0, 100))func main() { // ... for { select { case v := <-ch: buf = append(buf, v) if len(buf) == cap(buf) { // ... }}func doWrite() { for _, v := range buf { fmt.Fprintf(f, "%d ", v) // Write v to the file } buf = buf[:0] // "Clear" the buffer}With multiple goroutinesIf we stick to leave chInternal a channel, the doWrite() function may be called on another goroutine to not block the other one, e.g. go doWrite(). Since data to write is read from a channel (chInternal), this requires no further synchronization. 这篇关于在时间间隔和通道长度之间进行选择的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!
09-26 02:31