Below lists some frequently asked GoLang interview questions and their corresponding answers based on the author's experience. The list is updated frequently with new understandings. Stay tuned.
What is the GMP model of GoLang?
GoLang uses goroutine to achieve concurrency and it is famous for high concurrency support as the language defines its own goroutine dispatching and processing system which is well known as GMP model.
How it works is that M is normally defined as the OS thread being spawned( then each M thread should be associated with a Process queue and each Process queue can have multiple number of goroutines. The number or Process queues are defined with GOMAXPROCS()
. When a M processes all Gs from its associated P, it would steal Gs from other Ms and also the global P queue.
If a M hangs due to IO blocks or network blocks, it would detach itself from its P and this P will be associated with another available M or if it doesn’t exist, a new M will be created.
If a goroutine cannot be put into local P, it will be put in global P queue. If a M cannot steal G from other Ms, it would take from global P queue.
Each goroutine will only have 2K stack size which is pretty small and that’s why GoLang supports more concurrency. And this kind of switch between goroutine execution is based on the user thread space and hence the cost of switching context is not that high compared to thread or process
What is the GC mechanism in GoLang?
There are three phases: Mark Setup, Mark and Mark Termination. Mark Setup and Mark Terminations are STW. The Mark phase is concurrent.
When doing Mark Setup, a Write Barrier will be turned on to ensure data integrity and then it will wait for all running goroutines to stop.
When Marking starts, it will take 25% of CPU for itself and have a P for itself to do the collection. The marking phase will mark the head which is still in use, it tries to look through the stack of all goroutines and traverse its root pointer and then traverse from root and do the mark. In case the mark cannot finish in time, it will do Mark Assist which means asks other application goroutines to help. To speed mark up.
When doing Mark Termination, the Write Barrier is turned off and the clean ups will be done.
When to start to do GC?
- GC Percentage, where the percentage of new memory to be allocated compared to previous in-use memory during previous GC cycle.
- Manual trigger by calling runtime.GC()
How does a Slice work underlying?
A slice describes a piece of array and it’s not the same as array.
Slice header has length, capacity and also zeroth element pointer. Underlying it’s backed by an array. If capacity is reached, cannot grow anymore, need to recreate the underlying array and reallocate. If not reaching capacity, will be able to grow when needed.
Panic, defer and recover
For defer how it works FILO
-
A deferred function's arguments are evaluated when the defer statement is evaluated.
-
Deferred function calls are executed in Last In First Out order after the surrounding function returns
-
Deferred functions may read and assign to the returning function's named return values.
Panic will return execution and defers in the function will continue.
Recover is only useful inside deferred functions. In normal function, recover has no effect and does nothing.
Defer recover is working for the current goroutine only, it will not work for its spawned goroutine.
Context, it’s powerful
4 functions in the Context interface:
- Deadline(),
- Done(),
- Err(),
- Value(key interface{})
The benefit for this is resource sharing, goroutine control
There are derived goroutines such as WithCancel, WithDeadline, WithTimeout, WithValue
WithCancel:
-
Cancel function will be cascaded to sub-contexts
-
When a new sub-context is created it will be registered with the parent context.
WithValue
-
The key must be comparable as there is a c.key == key check when calling Value() function
-
The slice, map and function are not comparable. Mainly because slice is not comparable as it is a reference type where only comparing the address has no point and also the complexity increases for comparing contents in slice due to len/cap feature
Channel
Channel is a way to share memory by communication
There are buffered and non-buffered channel
- Close nil or closed channel will panic
- Send value to nil channel blocks forever, closed channel will panic
- Receive data from nil channel blocks forever, closed channel will return immediately
When would goroutine leak happen?
Some scenarios include:
- When channel is not closed while a goroutine keeps waiting for receiving data from channel
- When some resource is not closed properly while some goroutine still waits for response from the other side and there is no adequate timeout set for the blocking IO
What are the differences between new() and make()?
new()
will only allocate memory while make()
will initialize the data
Object created with new()
are ready to use but need to explicit initialize its properties before can use when needed
make()
can only be used on slice, map and channel types.
The detailed difference can be found here.
Differences between pointer and non-pointer method receiver?
It’s just like pass by reference vs pass by value in function calls.
If struct is to be mutated or the struct is too large for the receiver, one would choose to define pointer method receiver.
If some of the functions are having pointer receivers, the rest should have too to keep consistency.
How to check whether a struct implements an interface?
There is no implements keyword in GoLang like other languages such as Java. If a struct implements all methods of an interface, it is considered as implementing the interface. If the struct code is not at the same place as the interface definition, it might be difficult to find out whether a struct implements a specific interface. This might cause runtime problem in some cases.
There are a few ways to check that:
- Type assertion with dummy object.
var _ = (SomeStruct{}).(SomeInterface)
- Using reflection. reflect.TypeOf(OneInterface).Implements(reflect.TypeOf(SomeInterface).Elem())
For other methods, can find here.