2014-09-04 884 views
21

如何知道缓冲通道已满?我不知道在缓冲通道满时被阻塞,而是选择丢弃发送到缓冲通道的项目。Golang - 如何知道缓冲通道已满

+0

问题的前提是你想避免频道变满。但是,渠道*可以同步并因此阻止任何一方的事实是CSP思想的重要组成部分。不要过于努力,以防止缓冲区填满,直到您更全面地理解同步。作为练习,请尝试仅使用* unbuffered *通道解决几个问题。然后,您可以看到如何在现有的系统上添加缓冲功能可以提高性能。 (偶尔有太多缓冲可能会降低性能的情况。) – 2014-09-04 21:43:55

回答

56

您可以将select statement设为默认值。如果它是不可能做任何的情况下,如发送到一个完整的通道,该语句将做默认:

package main 

import "fmt" 

func main() { 
    ch := make(chan int, 1) 

    // Fill it up 
    ch <- 1 

    select { 
    case ch <- 2: // Put 2 in the channel unless it is full 
    default: 
     fmt.Println("Channel full. Discarding value") 
    } 
} 

输出:

通道全。丢弃值

游乐场:http://play.golang.org/p/1QOLbj2Kz2

检查而不发送

另外,也可以检查元件的数目在一个信道排队通过使用len(ch),如在Go specifications说明。 这与cap结合使我们能够检查一个通道是否已满而不发送任何数据。

if len(ch) == cap(ch) { 
    // Channel was full, but might not be by now 
} else { 
    // Channel wasn't full, but might be by now 
} 

注意,比较的结果可以通过时间是无效的,你进入if

+0

但是,如果只想检查缓冲区是否已满,即使没有写入缓冲区,该怎么办呢?有没有办法做到这一点? – Tom 2015-10-16 10:36:35

+9

@Tom你实际上可以测试'len(ch)== cap(ch){...}'其中'len(ch)'是频道中的项目数,cap(ch)'是容量。但是,输入if块时可能无效。 – ANisus 2015-10-16 11:11:09

+0

太棒了 - 现在这是一个完整的答案! – Tom 2015-10-16 19:47:32

10

,而不是我选择丢弃发送到缓冲通道的项目。

这就是所谓的 “爆棚通道”,你会发现蚤的答案eapache/channels/overflowing_channel.go实施:

for elem := range ch.input { 
    // if we can't write it immediately, drop it and move on 
    select { 
    case ch.output <- elem: 
    default: 
    } 
} 
close(ch.output) 

但该项目eapache/channels实现其他策略,以及:

  • OverflowingChannel实现Channel界面的方式永远不会阻止作者。
    具体来说,如果一个值在其缓冲区已满时写入OverflowingChannel
    (或者在未缓冲的情况下,当收件人未准备好时),那么该值将被简单地丢弃。

对于相反的行为(丢弃最旧的元件,而不是最新)看到RingChannel

+1

一个很好的答案。丢失最旧或最新项目的溢出通道有时可能是您工具箱中的重要工具。考虑一个goroutines环:通常,任何循环(a.k.a * cycle *)都存在死锁的风险。将任何一个频道更改为溢出频道都可以解决此问题。失去一些事件并不重要,如果他们是可以变得陈旧的种类可以很容易地被取代。当然有其他方法可以解决相同的死锁问题。 – 2014-09-04 21:39:09

1

我偶然发现的另一个有用的例子是this nifty implementationRing Buffer

从源引证:

的想法是简单的:通过一个 够程从输入信道到 输出信道将消息转发连接两台缓冲通道。无论何时在 传出通道上不能放置新消息,从传出通道中取出一条消息(即 是缓冲区中最旧的消息),放下它,并将新消息放入新释放的传出消息中渠道。

退房this C version以及...

0

使用len(channel)检查有多少元素在渠道目前和比较,为cap(channel),其容量:

func TestChannelFull(t *testing.T) { 
    chansize := 100 
    ch := make(chan bool, chansize) 
    t.Log(cap(ch)) 
    t.Log(len(ch)) 
    for len(ch) < cap(ch) { 
     ch <- true 
    } 
    t.Log(len(ch)) 
    t.Log("quit because channel is full") 
} 

init_test.go:25: 100 
init_test.go:26: 0 
init_test.go:30: 100 
init_test.go:31: quit because channel is full 
PASS