
Explore concurrency in Go, using built-in support and goroutines to divide a large workload into independent parts, enabling parallelism on multi-core processors while preserving correct results.
Explore Go's concurrency primitives and patterns, including goroutines, channels, mutexes, and the context package, with streaming pipelines, race detection, and practical examples like a web crawler and image processing pipeline.
Explore why Go uses concurrency primitives by reviewing processes and threads. Learn how the operating system's scheduler and context switching affect performance, including C10k limits.
Explore why concurrency is hard as shared memory among threads causes data races and non-deterministic outcomes. Learn how locks guard memory access, create exclusive sections, and trade parallelism for safety.
Explore how Go uses goroutines and channels, guided by CSP, to avoid shared memory and enable scalable concurrent data communication through lightweight user-space threads managed by the Go runtime.
Start goroutines using the go keyword to call a function, an anonymous function, or a function value, and observe interleaved output from concurrent execution with a sleep of 100 ms.
Build a tcp server on localhost:8000 using the net package, spawn goroutines to handle concurrent client connections, and run a client to receive responses.
Explore how wait groups in the sync package deterministically coordinate goroutines using add, done, and wait to join the main routine, preventing race conditions and nondeterministic execution.
Use a sync wait group to deterministically block the main routine until a goroutine increments shared data. The exercise demonstrates waiting for goroutines to complete to print the updated value.
Discover how goroutines run inside the creating function, directly modifying enclosing variables. See how the compiler pins variables to heap for access after return, ahead of the next coding exercise.
Explore how a goroutine can access a function's local variable after return through closure, as the runtime pins and moves i to the heap for continued access.
analyze a go concurrency exercise about closure and goroutines, showing how a loop variable is captured and printed, and fix by passing i as a parameter to each goroutine.
Explore how the Go runtime uses an M:N scheduler to map goroutines (G) onto OS threads (M) with processors (P) by gomaxprocs, featuring run queues and 10 ms preemption.
Explore how the Go scheduler handles synchronous system calls that block an OS thread during disk I/O, by moving the processor to a new thread and letting goroutines run.
Learn how Go uses netpoller to handle asynchronous system calls. The scheduler parks goroutines on non-ready file descriptors and notifies them via OS poll interfaces.
Explore how the Go scheduler uses work stealing to balance goroutines across logical processors, stealing from the local run queue or the global run queue to improve efficiency.
Explore how channels enable typed communication and synchronization between goroutines, how closing channels affects receive, and how receive returns a value plus an ok boolean.
Explore Go concurrency with channels by passing integer data between goroutines without shared memory, sending and receiving through a channel, and printing the result.
Learn how range over channel values stops when the channel closes, and how unbuffered and buffered channels affect blocking, capacity, and FIFO behavior.
Practice sending iterator values from a goroutine to a channel and receiving them in the main routine with range, printing each value and closing the channel to end the loop.
See how a goroutine uses a buffered channel to send six values without blocking. The main routine receives with range and prints the values.
Pass channels as function parameters with direction: receive-only or send-only to enforce type safety in Go. See how the compiler prevents sending on receive-only channels.
Practice channel direction in Go by relaying a message through two channels via goroutines, using send-only and receive-only channels to enforce type-safe, concurrent message passing.
Allocate channels with make, understand default nil values, and assign ownership to the creator for writing and closing to prevent deadlocks and panics.
Create a channel owner that returns a receive-only channel, spins a goroutine to send values and close the channel, and demonstrate consuming and printing them.
Explore how channels work in Go by examining the hchan structure created with make, a mutex lock, a ring buffer for buffered channels, and the waiting queues for blocked goroutines.
Examine a simple send and receive on a buffered channel driven by two goroutines, with elements copied into and out of the channel under a mutex, and no memory sharing.
Understand how a full buffered Go channel blocks the sender, stores the value in the buffer, and resumes when a receiver retrieves the data.
Explore the buffer empty channel scenario: a receiver goroutine parks in the receive queue, and a sender directly copies the value into the receiver's stack for performance.
Understand how unbuffered channels in Go synchronize goroutines through direct handoffs: senders write to waiting receivers or park in a send queue, and receivers copy data or park.
Understand the workings of channels in Go, including hchan, ring buffer, and mutex, how goroutines block on send and receive, and how the scheduler parks and resumes them in queues.
Explore how select handles multiple channel operations among goroutines, choosing randomly when multiple are ready, and how to implement timeouts and non-blocking communication with time.After and default cases.
Leverage go's select to multiplex receive from two string channels driven by goroutines at 1s and 2s, printing messages and iterating to capture two outputs in arrival order.
Implement a timeout on a channel receive in Go using select and time.After. The exercise shows a goroutine sending after two seconds and prints timeout if the three-second timeout elapses.
Explore non-blocking communication in Go by using select with a default case to receive from a channel without blocking the main routine, processing messages when available.
Learn how mutexes protect shared resources in Go, when to use mutex versus channels, and how read-write mutex allows multiple readers while a writer holds exclusivity.
Go concurrency with mutex guards balance, ensuring deposits and withdrawals occur inside a critical section protected by lock and unlock, preventing data races and yielding consistent results across goroutines.
Explore the atomic utilities in the sync package, performing lockless, concurrent safe memory operations with add and load to manage a counter across multiple goroutines.
Set gomaxprocs to four and run 50 goroutines, each incrementing a counter a thousand times, then apply the atomic package to perform thread-safe increments and obtain a consistent result.
Explore how conditional variables in Go enable synchronized goroutines with sync.Cond, using wait, signal, and broadcast to coordinate producer and consumer scenarios.
Coordinate a producer and consumer with a mutex and a conditional variable, using wait and signal to manage a shared resource.
Two goroutines wait on conditions with a mutex and a conditional variable. The main routine populates the shared resource and broadcasts to wake both producer and consumer goroutines.
Explore sync once and its do method to run one-time initialization across goroutines, ensuring a singleton object initialization even when called from multiple goroutines. This module includes coding exercises.
Learn how to guarantee a single execution of an initialization function across multiple goroutines using sync.Once and its Do method in Go.
Explore sync pool to constrain expensive resource creation by maintaining a fixed number of instances and reusing them through get and put methods, like database connections, network connections and memory.
Reuse bytes.Buffer instances with a sync.Pool in a log function, prefixing messages with the current time and writing to an io.Writer to reduce allocations.
Detect race conditions in Go with the race detector. Note that race-enabled binaries can be 10x slower and use 10x more memory, not for production; for integration and load testing.
Spot a data race between main goroutine and time after goroutines on timer t; fix by confining reads/writes to one goroutine and signaling via a bool channel to reset timer.
Explore a sequential Go web crawler that fetches pages, parses HTML, extracts links, and tracks visited URLs to crawl to a set depth, then demonstrates transitioning to parallel fetching.
Build a concurrent Go web crawler with goroutines and channels, using depth-controlled crawling and a fetch function. Boost speed by enabling GOMAXPROCS and parallel http get and html parse.
Explore Go's pipelines that connect stages with channels and goroutines to process streams and batches concurrently, using generators, square stages, and thumbnail image workflows, optimizing i/o and multiple CPU cores.
Build a three-stage Go pipeline with a generator, a square stage, and a print stage using goroutines and channels; connect stages to demonstrate composability and closing channels.
Explore fan-out and fan-in in Go pipelines by parallelizing a computationally intensive stage with multiple worker goroutines and merging results into a single channel to speed up the pipeline.
Fan out the square stage into two goroutines reading the same input channel and fan in results with a merge function that consolidates channels into one, using a wait group.
Learn how to cancel goroutines in a Go pipeline by closing a done channel to broadcast a stop signal, using select to exit early when downstream no longer needs values.
Cancel goroutines in a Go pipeline by introducing a done channel and passing it to all stages, using select to pre-empt sends and receives.
Questions that comes to all Developers is whether they are utilising the available Computing resource efficiently?
Course Overview
The course could be divided into five parts.
Concurrency Primitives
Deep Dive into Concurrency Primitives
Concurrency Patterns
Context Package
Bonus Section - Interfaces
In the course we try to answer these questions.
Concurrency Primitives
What are the limitations of Threads?
What are advantages of goroutines over OS threads?
How do we avoid race condition?
How Channels are used to communicate data?
How do we implement timeout and non-blocking communication?
When do we use mutex and channels?
How to synchronise execution of goroutines?
How to detect race condition in Go?
Deep Dives into Concurrency Primitives
How Go scheduler works?
How does context switching works?
How channel send and receive works underneath?
Concurrency Patterns
How to construct streaming pipelines with Goroutines and Channels?
How to Fan-out and Fan-in computationally intensive stages?
How do we avoid Goroutine Leaks?
Context Package
How we can propagate request scoped data and cancellation signal across API boundaries?
Coding Exercises
Each concept is followed by a Coding Exercise.
Exercises blueprint are shared on Github.
Sample Applications
We will build
Blueprint of web crawler.
Image processing pipeline.
HTTP Server Timeouts with Context Package.
Bonus Section - Interfaces
How to define common behaviour between different objects as abstract type?
How Interface provides an abstraction for higher level functions?