Can data coming from different channels into select statement get ignored? - go

Is it possible for data coming in through a channel in golang to get ignored if it is not caught at the right moment inside a select statement?
For example, lets say there is this select statement:
for {
select {
case <-timer.C:
//block A
default:
// block B takes 2 seconds.
}
}
If timer ends while block B is running, does block A still run in the next iteration of the loop or does the channel's incoming data get lost?

When the timer expires, it will send the current time on C. If no one is reading from C at the time, the send will block, so it will wait until the value is received. In this case, it will wait till the next iteration of the loop.
Channels are designed to be a synchronization mechanism, so they don't require readers and writers to be already synchronized.

Related

Clarification on Go channels tutorial from some missing word or words

This page on a Go Tutorial about channels seems to be missing a word(s) or was just not edited. I can't tell what it is supposed to say about sending and receiving through channels.
By default, sends and receives block until the other side is ready.
Is a block something within Go? I haven't seen it before. Is block being used as a noun?
I tried searching for clarification. The only other page that has similar wording is educative.io
Moreover, by default, channels send and receive until the other side is ready
But it doesn't make sense. Do they mean:
Channels send and receive regardless of whether or not the other side is ready? Doesn't this seem wasteful?
Or is "don't" missing in the statement above?
"Block" means that the goroutine will wait. You could write it this way:
By default, sends and receives wait until the other side is ready.
"Block" is just the normal term for this. It is not specific to Go. It is possible to use a channel in Go in a non-blocking manner:
You can create a channel with a buffer. As long as there is space in the buffer, a write is non-blocking (but it will block if the buffer is full). As long as there is data in the buffer, a read is non-blocking (but it will block if the buffer is empty).
You can use a select statement with a default branch.
var readch chan int
var writech chan int
var value int
select {
case n := <- readch:
// Received data.
case writech <- value:
// Sent data.
default:
// Didn't send or receive data.
}
In this code, instead of blocking (waiting), the goroutine will go to the default branch.

A question of running mechanism of select statement

When I read the docs of select section, there are some things that I really can't understand. With the docs (and the answer on StackOverflow), select will choose one case that could run (or won't block). If there are multiple case, Go will choose one of them random.
So, in my understanding, following cases should be run by random:
for {
select {
case <-time.After(time.Millisecond * 101):
fmt.Println("time out1")
case <-time.After(time.Millisecond * 100):
fmt.Println("time out2")
}
time.Sleep(time.Millisecond * 50)
}
But actually, it always print timed out2
why it only print timed out2, I think the first case also didn't block the program, If the golang could know how many time it will cost of the second case, how about replace this case to the operation which program can not know how many time will cost, like db operate, http request...
So I think, select always return that the fastest return?
time.After() returns a channel on which a value will be sent when the timeout expires.
So you have a select with 2 cases, where both receives from channels are blocking. So select blocks, waits until one of them can proceed.
Your 2 timeout values are different, so the smaller one will be ready to receive from sooner, so that case may be chosen immediately once the timeout expires.
Your loop body ends, and the next iteration begins. You create new timeout channels, so the same thing repeats.

How does Go select decide to run into the default branch?

I have a program in which I have 256 goroutines generating test data and sending them to a channel.
In the consuming part of the program, I set up a select like this:
select {
case c := <-theChan:
// Do some stuff with c
default:
//
}
What surprise me is that while the 256 goroutines keep sending items to the channel and the processing of the items take time? The program runs into the default branch several times.
I wonder how does the select statement decide that theChan is empty and run into default.
It depends on the scheduler, but between the time you consume a value from the channel and the time another goroutine gets execution time allocated by the scheduler (which would add a value in the channel), the main goroutine may have enough time to run the case and go back to the select statement before a value is added to the channel, it would then run the default case.
You could reduce this by using a buffered channel.

Executing code whilst waiting for a context cancel

Let's say I have a bunch of goroutines running that do a HTTP request and will return at a random time. I start the goroutines (with waitgroups and one cancel among them) and I want them to keep executing the request until it returns an OK (may time out). When the first one returns, it calls the cancel and every other goroutine should just stop.
I'm not sure how I can set up the goroutine function case that will execute the code if context is not done?
As an example, I know how to use time.After() but how do I make it such that it executes the code immediately instead of after a duration?
for {
select {
case <-ctx.Done():
wg.Done()
return
case <-time.After(time.Second):
// code goes here
}
}
What can I replace the time case with?
If I understand you correctly, you have multiple goroutines racing to compute the result to the same request. I believe you're looking for something like this:
for {
select {
case <-ctx.Done():
wg.Done()
return
default:
}
// Do stuff
}
The select will immediately drop to default if context is not canceled. However, context may still cancel while you're running your code, so you may end up with multiple goroutines trying to write the result, so you have to synchronize that as well. You can write your result to a channel, and when received, you can cancel the context. However you may still have goroutines waiting to write to that channel, so you have to keep reading from the channel until all goroutines terminate.

whats the difference between for loop with select and only select?

Could not fully understand it from the docs or google:
What are the differences between the two and in
Which case would you use each one?
for{
select{
case s := <-something:
fmt.Println(s)
case done := <-true:
return
}
}
and
select{
case s := <-something:
fmt.Println(s)
case done := <-true:
return
}
Thanks
Code with loop will keep printing data from channel something until it receives anything on channel done.
Select-only code will either print data from channel something or will quit when it receives anything on channel done. Only one case will be executed. Keep in mind there is no fallthrough in Go select and switch statements by default.
select statement executes through its cases (sending/receiving a the channel) once. If none of its cases are ready to be executed, it blocks until at least one of the case is ready to execute. If more than one cases are ready at the same time, one of the ready case is selected to be executed at random.
So in second case, if there is some data on the something channel, it would be read and put into s. But there is also a chance of true being sent on done while the case s := <-something: will never be executed.
In the first case, you probably want something like this (also in second case):
for{
select{
case s := <-something:
fmt.Println(s)
case <-done: // note the difference
return
}
}
What this now does is that it waits for data on something and also keeps an eye on done. If there is data on something channel (and no data on done), it will be read and put into s (case branch case s := <-something: will be executed with s having the value read from something). This will account for one full execution of select statement and the control will go back to for loop and it will start over again.
If there is no data on something channel, select blocks and waits for data on either something or done. If data arrives on something, similar execution as above happens, otherwise if it arrives in done, the function returns (breaks out of loop). This way some other process can write to done and signal the function containing above for loop to stop processing something and return.
If your program sends data to the 'something' channel a bunch of times you are going to want to repeat the select clause until you receive a done signal.
For example imagine you are running the following routine
.... (some calculations)
something <- x
.... (some calculations)
something <- y
true <- z
If your routine doesn't have the for loop it will only receive the value 'x' and won't receive y or z.

Resources