How to receive from channel till it has values in GO - go

A function has loop which call a go routine inside it with a channel passed into it.
After this, I try receiving from channel till it has values.
The go function passes value in channel upon each call.
My channel runs infinitely.
func (m *StreamsDAO) FindOutput(input model.Input) ([]model.Output, error) {
// SOME CODE
var chanNumber int = (input.EndTime - input.StartTime)/60
outputChan := make(chan model.Output, chanNumber)
for i := input.StartTime; i < input.EndTime ;i = i+(slider*60) {
// SOME CODE
go ForEachSlide(i, outputChan)
for outputC := range outputChan {
outputs = append(outputs, outputC)
}
}
return outputs, err
}
func ForEachSlide(i int, outputChan chan model.Output) {
// SOME CODE
outputChan <- output
// close(outputChan)
}
Its looping infinite as there in no stop for receiving from channel.
If close channel is used, only single element is received from channel thats as expected, but I need all values from the channel.

Related

Streaming data over go channel

I'm trying to build a function that I pass a channel to and when run in a go routine it will constantly post updates (in this instance, values of sin) to a channel. When data is sent the the channel, I then want to send it over a web socket.
func sineWave(value chan float64) {
var div float64
sinMult := 6.2839
i := 0
log.Println("started")
for {
div = (float64(i+1) / sinMult)
log.Println(math.Sin(div))
time.Sleep(100 * time.Millisecond)
value <- math.Sin(div)
// log.Println()
i++
if i == 45 {
i = 0
}
}
// log.Println(math.Sin(div * math.Pi))
}
It seems to get stuck at value <- main.Sin(div) stopping the rest of main() from running. How do i get sineWave to run indefinitely in the background and to print its output in another function as they arrive?
There is several mistakes in this code,
the value chan is never drained, so any write will block
the value chan is never closed, so any drain will be infinite
A channel must always be drained, a channel must be closed at some point.
Also, please post reproducible examples, otherwise it is difficult to diagnose the issue.
This is a slightly modified but working version of the OP code.
package main
import (
"fmt"
"math"
"time"
)
func sineWave(value chan float64) {
defer close(value) // A channel must always be closed by the writer.
var div float64
sinMult := 6.2839
i := 0
fmt.Println("started")
for {
div = (float64(i+1) / sinMult)
time.Sleep(100 * time.Millisecond)
value <- math.Sin(div)
i++
if i == 4 {
// i = 0 // commented in order to quit the loop, thus close the channel, thus end the main for loop
break
}
}
}
func main() {
value := make(chan float64)
go sineWave(value) // start writing the values in a different routine
// drain the channel, it will end the loop whe nthe channel is closed
for v := range value {
fmt.Println(v)
}
}

Receiving values from goroutine for certain amount of time

I have a goroutine which can generate an infinite number of values (each more suitable than the last), but it takes progressively longer to find each values. I'm trying to find a way to add a time limit, say 10 seconds, after which my function does something with the best value received so far.
This is my current "solution", using a channel and timer:
// the goroutine which runs infinitely
// (or at least a very long time for high values of depth)
func runSearch(depth int, ch chan int) {
for i := 1; i <= depth; i++ {
fmt.Printf("Searching to depth %v\n", i)
ch <- search(i)
}
}
// consumes progressively better values until the channel is closed
func awaitBestResult(ch chan int) {
var result int
for result := range ch {
best = result
}
// do something with best result here
}
// run both consumer and producer
func main() {
timer := time.NewTimer(time.Millisecond * 2000)
ch := make(chan int)
go runSearch(1000, ch)
go awaitBestResult(ch)
<-timer.C
close(ch)
}
This mostly works - the best result is processed after the timer ends and the channel is closed. However, I then get a panic (panic: send on closed channel) from the runSearch goroutine, since the channel has been closed by the main function.
How can I stop the first goroutine running after the timer has completed? Any help is very appreciated.
You need to ensure that the goroutine knows when it is done processing, so that it doesn't attempt to write to a closed channel, and panic.
This sounds like a perfect case for the context package:
func runSearch(ctx context.Context, depth int, ch chan int) {
for i := 1; i <= depth; i++ {
select {
case <- ctx.Done()
// Context cancelled, return
return
default:
}
fmt.Printf("Searching to depth %v\n", i)
ch <- search(i)
}
}
Then in main():
// run both consumer and producer
func main() {
ctx := context.WithTimeout(context.Background, 2 * time.Second)
ch := make(chan int)
go runSearch(ctx, 1000, ch)
go awaitBestResult(ch)
close(ch)
}
You are getting a panic because your sending goroutine runSearch apparently outlives the timer and it is trying to send a value on the channel which is already closed by your main goroutine. You need to devise a way to signal the sending go routine not to send any values once your timer is lapsed and before you close the channel in main. On the other hand if your search gets over sooner you also need to communicate to main to move on. You can use one channel and synchronize so that there are no race conditions. And finally you need to know when your consumer has processed all the data before you can exit main.
Here's something which may help.
package main
import (
"fmt"
"sync"
"time"
)
var mu sync.Mutex //To protect the stopped variable which will decide if a value is to be sent on the signalling channel
var stopped bool
func search(i int) int {
time.Sleep(1 * time.Millisecond)
return (i + 1)
}
// (or at least a very long time for high values of depth)
func runSearch(depth int, ch chan int, stopSearch chan bool) {
for i := 1; i <= depth; i++ {
fmt.Printf("Searching to depth %v\n", i)
n := search(i)
select {
case <-stopSearch:
fmt.Println("Timer over! Searched till ", i)
return
default:
}
ch <- n
fmt.Printf("Sent depth %v result for processing\n", i)
}
mu.Lock() //To avoid race condition with timer also being
//completed at the same time as execution of this code
if stopped == false {
stopped = true
stopSearch <- true
fmt.Println("Search completed")
}
mu.Unlock()
}
// consumes progressively better values until the channel is closed
func awaitBestResult(ch chan int, doneProcessing chan bool) {
var best int
for result := range ch {
best = result
}
fmt.Println("Best result ", best)
// do something with best result here
//and communicate to main when you are done processing the result
doneProcessing <- true
}
func main() {
doneProcessing := make(chan bool)
stopSearch := make(chan bool)
// timer := time.NewTimer(time.Millisecond * 2000)
timer := time.NewTimer(time.Millisecond * 12)
ch := make(chan int)
go runSearch(1000, ch, stopSearch)
go awaitBestResult(ch, doneProcessing)
select {
case <-timer.C:
//If at the same time runsearch is also completed and trying to send a value !
//So we hold a lock before sending value on the channel
mu.Lock()
if stopped == false {
stopped = true
stopSearch <- true
fmt.Println("Timer expired")
}
mu.Unlock()
case <-stopSearch:
fmt.Println("runsearch goroutine completed")
}
close(ch)
//Wait for your consumer to complete processing
<-doneProcessing
//Safe to exit now
}
On playground. Change the value of timer to observe both the scenarios.

goroutine that takes a channel receiver and sends string to channel

I am trying to make a loop of goroutines that take a channel that receives strings, and every time it is received it should append the value to another string. Only at the end of all goroutines (the goroutine count should be the length of the list passed in), should the code continue on.
My example below doesn't seem to append the values from the strReceiver channel onto str, because str is never modified.
Anyone know what's wrong?
func appendToStr(str string, list []string, origin *url.URL) {
var currProc int32 = 0;
var maxProc int32 = int32(len(list))
var strReceiver := make(chan string, len(list))
for _, item := range list {
go func() {
doAsyncAndIncrement(item, strReceiver, &currProc)
str += <-strReceiver
}()
}
for {
if atomic.LoadInt32(&currProc) <= maxProc {
break;
}
}
// continue on using 'str' which now contains the append values from the 'strReceiver' channel
}
func doAsyncAndIncrement(item string, receiver chan<- string, count *int32) {
defer atomic.AddInt32(count, 1)
var val string
// do something with 'item' and set 'val'...
receiver <- val
}
One problem with your code is that the closure around your go routine invocation is too big.
for _, item := range list {
go func() {
doAsyncAndIncrement(item, strReceiver, &currProc)
str += <-strReceiver
}()
}
item is scoped to the for loop, not the anonymous function in your goroutine, so while you firing off N goroutines, your item variable meanwhile is being updated in a for loop. To remedy this, pass the variable to your goroutine explicitly, to avoid using a closure:
for _, item := range list {
go func(item string) {
doAsyncAndIncrement(item, strReceiver, &currProc)
str += <-strReceiver
}(item)
}

Go routine not receiving all data sent through channel — toy example program

I'm just playing around with Go, taking it for a test drive so to speak. I'm having a problem where a go routine that is mean to receive 3 integers only seems to receive one.
type simpleFunction func() int
func run(fChan chan simpleFunction, result chan int) {
for{
select {
case fn := <-fChan:
fmt.Printf("sending: %d down result chan\n", fn())
result <- fn()
case <-time.After(time.Second * 2):
close(fChan)
}
}
}
func recieve(result chan int){
for {
select {
case x := <-result:
fmt.Printf("recieved: %d from result chan\n", x)
case <-time.After(time.Second * 2):
close(result)
}
}
}
So, as you can see the run routine receives functions, evaluates them, and then sends the result down the result channel.
Here's my main/test:
func main() {
fns := []simpleFunction{
func() int {return 1},
func() int {return 2},
func() int {return 3},
}
fChan := make(chan simpleFunction)
result := make(chan int)
go run(fChan, result)
go recieve(result)
for _, fn := range fns {
fmt.Printf("sending a function that returns: %d down function chan\n", fn())
fChan <- fn
}
}
And here's my output:
sending a function that returns: 1 down function chan
sending: 1 down result chan
recieved: 1 from result chan
sending a function that returns: 2 down function chan
sending a function that returns: 3 down function chan
sending: 2 down result chan
sending: 3 down result chan
So, as you can see, everything seems to go swimmingly for the first function, but it's not so hot afterwards. Any tips or suggestions?
There are a couple of issues with this code:
The program terminates when main returns. It does not wait for the run and receive goroutines to complete.
There's a race on closing the channels. There's no guarantee that the sender will top sending before the timeout.
If main does not exit, then the for { select { } } loops will spin forever printing zero values. Receive on a closed channel returns the zero value.

Why never reached the return statement

Look at the following code snippet
package main
import (
"fmt"
"time"
)
func sender(ch chan string) {
ch <- "Hello"
ch <- "Foo"
ch <- "and"
ch <- "Boo"
close(ch)
}
func main() {
ch := make(chan string)
go sender(ch)
for {
select {
case value := <-ch:
fmt.Println(value)
case <-time.After(time.Second * 2):
fmt.Println("Return")
return
}
}
}
As result I've got blank output and the time.After will be never reached. Why?
I notice, when I try to receive value from a closed channel, it will receive the zero value from the type. Why can I still receive value from a closed channel?
I can check also like is too,
v, ok := <-ch
if ok is false, the channel is closed.
A new two second timer is created on every iteration of the for loop. Closed channels are always ready to receive. The code loops forever because the channel for the new timer is never ready to receive before the closed channel is ready to receive.
One way to fix the problem is to set the channel to nil:
case value, ok := <-ch:
if !ok {
ch = nil
} else {
fmt.Println(value)
}
Receive on a nil channel is never ready.
playground example
If you wanted the loop to run for at most two seconds, then you should create the timer outside of the loop:
after := time.After(time.Second * 2)
and select on this one timer in the loop:
case <-after:
fmt.Println("Return")
return
playground example (sleep added to make example run on playground)
You can combine setting the channel to nil and creating the timer outside of the loop.
playground example

Resources