Use linked channels for data broadcast in Go

Source: Internet
Author: User
This is a creation in Article, where the information may have evolved or changed.

Use linked channels for data broadcast in Go

The original is here (need to turn over the wall), why want to translate this article is because in practice has encountered such problems, and the article is a clever way to solve, I hope to be useful to everyone.

Channels is a powerful thing in go, but there are limitations in dealing with something. One of them is a pair of more communications. Channels works well under several writers, a reader model, but it is not easy to handle multiple reader waits for a writer to send the data.

To handle this scenario, a possible Go API prototype is as follows:

type Broadcaster …func NewBroadcaster() Broadcasterfunc (b Broadcaster) Write(v interface{})func (b Broadcaster) Listen() chan interface{}

The broadcast channel is created through Newbroadcaster and is broadcast through the Write function. To listen to this channel information, we use listen, which returns a new channel to accept the data sent by write.

This solution requires an intermediate process to handle all reader registrations. When the call to listen creates a new channel, the channel is registered, usually the main loop of the intermediate process is as follows:

for {    select {        case v := <-inc:            for _, c := range(listeners) {                c <- v            }        case c := <- registeryc:            listeners.push(c)    }}

This is a common practice (translators often do the same). However, the process blocks when processing data broadcasts until all readers read the value. An optional solution is that reader's channel is buffer buffered, buffer size we can adjust on demand. Or we discard the data when the buffer is full.

But this blog is not about this set of practices. This blog mainly proposes another way to achieve writer never block, a slow reader does not because the writer sends the data too fast to consider allocating too large buffer.

Although this does not have too high performance, but I do not care, because I think it is cool. I'm sure I'll find a good place to use it.

The first is the core thing:

type broadcast struct {    c chan broadcast    v interface{}}

This is what I call the linked channel, but in fact it is OUROBOROS data structure. That is, the struct instance contains itself when it is sent to the channel.

On the other hand, if I have a Chan broadcast type of data, then I can read a broadcast B,B.V is the arbitrary data that writer sends, and B.C, the original Chan broadcast, can let me repeat the process.

Another area that may be confusing is that a channel with a buffer can be used as a 1-to-many broadcast object. If I define the following buffered channel:

var c = make(chan T, 1)

Any process that attempts to read C will block until there is data written to it.

When we want to broadcast a data, we simply write it to the channel, and this value is only obtained by a reader, but we agreed that as soon as we read the data, we immediately put it in the channel again, as follows:

func wait(c chan T) T {    v := <-c    c <-v    return v}

Combined with the above two discussions, we can see that if the channel inside the broadcast struct can be processed in the way above, we can implement a data broadcast.

code is as follows:

Package Broadcasttype broadcast struct {C Chan broadcast; V interface{};}    Type broadcaster struct {//private Fields:listenc Chan Chan (Chan broadcast); SENDC chan<-interface{};} Type Receiver struct {//private FIELDS:C Chan broadcast;}    Create a new broadcaster Object.func Newbroadcaster () broadcaster {listenc: = Make (Chan (Chan broadcast));    SENDC: = Make (chan interface{});        Go func () {CURRC: = Make (chan broadcast, 1); For {select {case V: = <-sendc:if v = = Nil {CURRC <-bro                    adcast{};                Return                } c: = Make (chan broadcast, 1);                B: = Broadcast{c:c, v:v};                CURRC <-B;            CURRC = C;    Case r: = <-listenc:r <-CURRC}}} (); Return broadcaster{Listenc:listenc, SENDC:SENDC,};} Start listening To the Broadcasts.func (b broadcaster) Listen () Receiver {c: = Make (Chan Chan broadcast, 0);    B.listenc <-C; Return receiver{<-c};} Broadcast a value to all Listeners.func (b broadcaster) Write (v interface{}) {B.sendc <-v}//read a value that have been broadcast,//waiting until one is available if Necessary.func (R *receiver) Read () interface{} {b: = <-r.c    ;    V: = B.V;    R.C <-B;    R.C = B.C; return v;}

The following is the translator's thing, this set of ways to achieve very ingenious, first of all it solves the reader register and unregister problems. Second, I think it's a good use of streaming, when reader reads a value, reader can pass it to the next reader to continue to use, while they start listening to the next new value of the arrival.

A test case for the translator himself:

func Testbroadcast (t *testing. T) {b: = Newbroadcaster () r: = B.listen () b.write ("Hello") if R.read (). ( String)! = "Hello" {t.fatal ("error string")} R1: = B.listen () b.write (123) if R.read (). (int)! = 123 {t.fatal ("error int")} if R1. Read ().    (int)! = 123 {t.fatal ("error int")} b.write (nil) if R.read ()! = nil {t.fatal ("Error nit")} If R1. Read ()! = nil {t.fatal ("Error nit")}}  

Of course, this approach is still a bit inadequate, mainly in the receiver read function, and can not be very good integration with select, specific reference to the author of another article bloghttp:// rogpeppe.wordpress.com/2010/01/04/select-functions-for-go/.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.