在时间间隔和通道长度之间进行选择

在时间间隔和通道长度之间进行选择,第1张

在时间间隔和通道长度之间进行选择

没有“ 通道缓冲区已满” 这样的“事件” ,因此您无法检测到[*]。这意味着您不能仅使用1个通道就用语言原语惯用地解决您的问题。

[*]并非完全如此:你可以检测一个信道的缓冲区已满通过使用

select
default
当情况下 发送
的信道上,但是这需要从发送者,并重复尝试发送逻辑。

我将使用从中接收值发送的另一个通道,然后“重定向”,将值存储在另一个通道中,该通道的缓冲区为100,如您所提到的。在每次重定向时,您都可以检查内部通道的缓冲区是否已满,如果已满,请立即进行写 *** 作。如果不是,请继续使用

select
语句监视“传入”通道和计时器通道,如果计时器启动,则执行“常规”写入

您可以

len(chInternal)
用来检查
chInternal
通道中有多少个元素,并
cap(chInternal)
检查其容量。请注意,这是“安全的”,因为我们是唯一处理该
chInternal
通道的goroutine
。如果将有多个goroutine,则
len(chInternal)
在我们将其用于某些事物时(例如,对其进行比较),返回的值可能已过时。

在此解决方案中

chInternal
(顾名思义)仅供内部使用。其他人只能在上发送值
ch
。请注意,
ch
可能是缓冲通道,也可能不是缓冲通道,在两种情况下解决方案均有效。但是,如果您还提供一些缓冲,则可以提高效率
ch
(这样,发件人被阻止的机会就会减少)。

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)        }    }}

如果立即写入(由于“缓冲区已满”的情况),此解决方案将在此之后5秒钟对下一次“常规”写入进行计时。如果您不希望这样做,并且希望5秒钟常规写入独立于立即写入,则只需在立即写入后不重置计时器即可。

的实现

doWrite()
可能如下:

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        }    }}

我们不能使用

for ...range
该方法,因为它仅在关闭通道时返回,而我们的
chInternal
通道没有关闭。因此,我们使用
select
带有的
default
情况,以便当的缓冲区中没有更多值时
chInternal
,我们返回。

改进之处使用切片而不是第二通道

由于

chInternal
通道仅由我们使用,并且仅在单个goroutine上使用,因此我们也可以选择使用单个
[]int
片而不是通道(读/写片比通道快得多)。

仅显示不同/已更改的部分,看起来可能像这样:

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}
有多个goroutines

如果我们坚持离开

chInternal
一个通道,则
doWrite()
可以在另一个goroutine上调用该函数以不阻塞另一个通道,例如
godoWrite()
。由于要从通道(
chInternal
)读取要写入的数据,因此不需要进一步的同步。



欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/zaji/5010259.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-11-14
下一篇 2022-11-14

发表评论

登录后才能评论

评论列表(0条)

保存