14. Mistakes?
Go’s official documentation states that “A common Go newbie mistake is to
over-use channels and goroutines just because it’s possible, and/or
because it’s fun.”
Let’s get the obligatory share memory by blah blah blah out of the way
We have all heard it – waay to many times I would add
So let’s just get it over with
They can only transfer data of ONE data type
Before talking about channels – let’s quickly go over goroutines
L1 Cache is 0.5 ns
L2 cache is 7ns
Packet from CA to Netherlands to CA is ~150ms
They can only transfer data of ONE data type
Prints nil
Zero value of a channel is nil
Use a make
Channels by default are pointers – so if you print you’ll see a memory address
Allocates on the heap
Look at the direction of the arrow
Write to a channel
Read from a channel
Look at the direction of the arrow
Write to a channel
Read from a channel
Look at the direction of the arrow
Write to a channel
Read from a channel
You don’t have to
They are not file handles
Its not the same as a http connection, socket, database or redis or file
Its just a way to tell the receivers that the sending is finished
The resource will get Gced
Writing to a close channel is a panic – your app will crash
Depends
If you are doing 2+2 then yeah
But if you are doing an expensive blocking call like an http get then no
A lot of go devs get into the language because of goroutines and channels
Have an array of URLs – do parallel get requests or downloads
Do not over use channels because of the novelty
Let’s look at the chan internals now
When you write this – you get a pointer back
The only things to keep in mind here is the buf which is a circular queue
The sendx and receivex which are the indices to that buffer
The recvq and sendq which keep track of goroutines which we will see in a bit
Waitq is a sudog struct
And the lock which is a mutex
This is the actual goroutine struct
And this is the sudog which was the waitq in the channel
G is the goroutine and elem is the data which we will see how that works
The elem is an unsafe pointer – because you can make channels of any type – so its basically like generics or a void in C
So this is what a channel is
Lets look at how do you write to channel
Copy the data
Release the lock
Ez pz
Ez pz
What about reads?
lock
read
Release lock
Ez pz
So lets look at the indices now
When you make a channel this is what gets made – a crcular queue – send and receive indices and a lock
If I do an enque – write to the buffer
And update send x to 1
Add two more now full
So send x is now 0
When you read from a channel – it does a deque
And changes recevx to 1
Two more reads – two more deques
So now recevx is back to 0
From the day we are born we are taught that writing to a full channel is a blocking operation
Readfing from an empty channel is a blocking operation
So now the buffer is full and we are trying to write to it
We know this is a blocking operation – but how does the runtime scheduler do it
Quick break to talk about the go runtime scheduler
So now the buffer is full and we are trying to write to it
We know this is a blocking operation – but how does the runtime scheduler do it
This is super useful
The goroutine is blocked not the thread - so we are still using resources optimally
Now I need to setup state so that goroutine can be resumed later on somehow
Remember the sudog element from before
Now there is a slot open
Now when some one comes and reads the buffer
There is space again
The dequee is the read
So we put the elem in the slot that just opened up by popping the sendq
And then set g1 to be ready
And add back to the q to be scheduled later
If there were multiple goroutines blocked – since it’s linkedlist/FIFO – the earliest one gets put on first
They can only transfer data of ONE data type
We are trying to receive on an empty channe so it blocks
On the receivng side it’s the opposite
We put the sudog struct on the recevq
And now when someone comes to read it we can either write it to the buffer and then read from there
Or we can be smarter and use the address of the memory location we have and write it there directly
The goroutine will write it into the other goroutine’s stack space directly