1

I need several functions to have the same channel as a parameter and take the same data, simultaneously. Each of these functions has an independent task from each other, but they start from the same value.

For example, given a slice of integers, one function calculates the sum of its values ​​and another calculates the average, at the same time. They would be goroutines.

One solution would be to create multiple channels from one value, but I want to avoid that. I might have to add or remove functions and for this, I would have to add or remove channels.

I think I understand that the Fan Out pattern could be an option, but I can't quite understand its implementation.

Jumanyi
  • 375
  • 1
  • 2
  • 9
  • 2
    Possible duplicate [How to broadcast message using channel](https://stackoverflow.com/questions/36417199/how-to-broadcast-message-using-channel/49877632?r=SearchResults#49877632). – icza Sep 19 '20 at 18:00
  • The examples posted are complex to my current understanding. Anyway, I am studying the code that you indicate. The case that I put as an example aimed to see if there is an explanation as simple as possible. Thank you anyway. – Jumanyi Sep 19 '20 at 18:32

1 Answers1

1

The question is against the rules of SO—as it does not present any concrete problem to be helped with but rather requests a tutoring session.

Anyway, two pointers for further research: basically—given the property of channel that each receive consumes a value sent to it, so it's impossible to read a once sent value multiple times,—such problems have two approaches to their solutions.

The first approach, which is what called a "fan-out", is to have all the consumers have a "personal" dedicated channel, copy the value to be broadcast as many times as there are consumers and send each copy to each of those dedicated channels.

The ostensibly most natural way to implement this is to have a single channel to which the producer sends its units of work—not caring how much consumers are to read them—and then have a dedicated goroutine receive those units of work, copy each of them and send the copies out to the dedicated channels of the consumers.

The second approach is to go lower level and implement basically the same scheme using stuff from the sync package.

One can think of the following scheme:

  • Have a custom struct type which has a sync.Mutex protecting the type's state.
  • Have a field which keeps the value multiple consumers have to read.
  • Have a counter in that type.
  • Have a sync.Cond in that type as well.
  • Have a channel with capacity there 1 as well.

Communicating a new value to the consumers looks like this:

  1. Lock the mutex.
  2. Verify the counter is 0, panic otherwise.
  3. Write the new value into the respective field.
  4. Set the counter to the number of consumers.
  5. Unlock the mutex.
  6. Pulse the sync.Cond.

The consumers are supposed to sleep in a wait call on that sync.Cond.
Once the sender pulses it, the goroutines running the code of consumers get woken up and try to read the value.
Reading of the value rolls like this:

  1. Lock the mutex.
  2. Verify the counter is greater than zero, panic otherwise.
  3. Read the value.
  4. Decrement the counter by one.
  5. If the counter becomes 0, send on that special channel.
  6. Unlock the mutex.

The channel is needed to communicate to the sender that all the consumers are done with their reads: before attempting to send the new value the consumer has to read from that channel.

As you can probably see, the second approach is way more involved and hard to get right, so I'd recommend to go with the first one.


I would also note that you seem to lack certain background knowledge on how to go around implementing concurrently running and communicating tasks.
I hereby recommend reading The Book and at least these chapters of The Blog:

kostix
  • 51,517
  • 14
  • 93
  • 176
  • I appreciate the information and advice you give me. I have no training in the matter. I started reading about programming a few months ago. Go is my first language. I try to learn by reading articles and simple examples. Sometimes, I try to take a bigger step than I can. It`s a personal challenge at my 52 years. Thanks again!! – Jumanyi Sep 20 '20 at 15:10
  • @Jumanyi, well, kudos for your embarking then! That is really cool! Still, tread your path gradually. It's best to move in small concrete steps to build the experience up without gaps. I heartily recommend the book I referred to but you can also get good books from [this list](https://github.com/golang/go/wiki/Books) (I would recommend the one by Caleb Doxsey). Also be sure to read ["Effective Go"](https://golang.org/doc/effective_go.html). – kostix Sep 20 '20 at 19:59
  • I mean, concurrent programming is not rocket science but it's tricky and requires solid foundation in "basic" "single-threaded" programming. You might want to also read some material on what concurrency looks "on the metal" and the OS level—read about CPU caches, memory access, locks etc: this greatly eases understanding of why channels and stuff from the `sync` package in Go are needed. – kostix Sep 20 '20 at 20:02