{"id":1088,"date":"2026-08-17T00:40:51","date_gmt":"2026-08-17T00:40:51","guid":{"rendered":"https:\/\/www.devopsschool.com\/tutorials\/?p=1088"},"modified":"2026-08-17T00:40:52","modified_gmt":"2026-08-17T00:40:52","slug":"go-tutorials-concurrency-made-simple","status":"publish","type":"post","link":"https:\/\/www.devopsschool.com\/tutorials\/go-tutorials-concurrency-made-simple\/","title":{"rendered":"Go Tutorials: Concurrency Made Simple"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">This tutorial covers:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Goroutines<\/li>\n\n\n\n<li>Channels<\/li>\n\n\n\n<li>Channel Direction<\/li>\n\n\n\n<li><code>select<\/code><\/li>\n\n\n\n<li>Worker Pools<\/li>\n\n\n\n<li>Fan-out \/ Fan-in<\/li>\n<\/ol>\n\n\n\n<p class=\"wp-block-paragraph\">The goal is simple:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\"><strong>One concept \u2192 one mental model \u2192 one complete example.<\/strong><\/p>\n<\/blockquote>\n\n\n\n<p class=\"wp-block-paragraph\">Every example is independent. You can copy it into <code>main.go<\/code> and run:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>go run main.go<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">0. First Understand the Big Picture<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Before looking at code, remember these six ideas:<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th>Concept<\/th><th>Think of it as<\/th><\/tr><\/thead><tbody><tr><td>Goroutine<\/td><td>A lightweight worker<\/td><\/tr><tr><td>Channel<\/td><td>A pipe between workers<\/td><\/tr><tr><td>Channel direction<\/td><td>Making a pipe send-only or receive-only<\/td><\/tr><tr><td><code>select<\/code><\/td><td>Waiting on multiple pipes<\/td><\/tr><tr><td>Worker pool<\/td><td>A fixed number of workers sharing jobs<\/td><\/tr><tr><td>Fan-out \/ Fan-in<\/td><td>Split work between workers, then combine results<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">A useful mental picture:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>flowchart LR\n    A&#91;Main Program] --&gt; B&#91;Goroutines]\n    B --&gt; C&#91;Channels]\n    C --&gt; D&#91;Channel Direction]\n    C --&gt; E&#91;select]\n    B --&gt; F&#91;Worker Pool]\n    B --&gt; G&#91;Fan-out \/ Fan-in]<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">One important distinction:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\"><strong>Concurrency does not necessarily mean things execute at exactly the same instant.<\/strong><\/p>\n<\/blockquote>\n\n\n\n<p class=\"wp-block-paragraph\">Concurrency means multiple tasks can make progress independently.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">1. Goroutines<\/h1>\n\n\n\n<h2 class=\"wp-block-heading\">What?<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">A <strong>goroutine<\/strong> is a function that runs concurrently with other functions.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Normally:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>doWork()<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Go waits for <code>doWork()<\/code> to finish.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">But:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>go doWork()<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">starts <code>doWork()<\/code> as a goroutine and continues executing the next line.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Why?<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Imagine your application needs to:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>process a request<\/li>\n\n\n\n<li>save something<\/li>\n\n\n\n<li>send an email<\/li>\n\n\n\n<li>perform another independent task<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">You may not want every task to block everything else.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Goroutines allow independent work to run concurrently.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">When?<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Use goroutines when tasks can run independently.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Examples:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>handling multiple HTTP requests<\/li>\n\n\n\n<li>processing background jobs<\/li>\n\n\n\n<li>making multiple API calls<\/li>\n\n\n\n<li>reading data from multiple sources<\/li>\n\n\n\n<li>processing files<\/li>\n\n\n\n<li>running workers<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">How?<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Put <code>go<\/code> before a function call:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>go myFunction()<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Where?<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Goroutines are heavily used in:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>web servers<\/li>\n\n\n\n<li>network services<\/li>\n\n\n\n<li>background processors<\/li>\n\n\n\n<li>message consumers<\/li>\n\n\n\n<li>concurrent applications<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Complete Example<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>package main\n\nimport (\n\t\"fmt\"\n\t\"sync\"\n)\n\nfunc sayHello() {\n\tfmt.Println(\"Hello from goroutine\")\n}\n\nfunc main() {\n\n\tvar wg sync.WaitGroup\n\n\t\/\/ We are starting 1 goroutine.\n\twg.Add(1)\n\n\tgo func() {\n\n\t\t\/\/ Tell WaitGroup that this goroutine\n\t\t\/\/ has finished when the function ends.\n\t\tdefer wg.Done()\n\n\t\tsayHello()\n\n\t}()\n\n\tfmt.Println(\"Hello from main\")\n\n\t\/\/ Wait until the goroutine finishes.\n\twg.Wait()\n}<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Possible output:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Hello from main\nHello from goroutine<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">You may occasionally see the order reversed.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">That is normal.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The goroutine and <code>main()<\/code> are running concurrently.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Mental Model<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Think:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>main()\n  |\n  |---- worker goroutine\n  |\n  |---- main continues<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The important syntax is simply:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>go function()<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">2. Channels<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Now we have a problem.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">If goroutines are independent workers:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\">How do they safely communicate?<\/p>\n<\/blockquote>\n\n\n\n<p class=\"wp-block-paragraph\">That is where <strong>channels<\/strong> come in.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">What?<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">A channel is a typed communication pipe between goroutines.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">One goroutine can:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>SEND ---&gt; channel ---&gt; RECEIVE<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">For example:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Goroutine A\n    |\n    | \"hello\"\n    v\n  Channel\n    |\n    v\nGoroutine B<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Why?<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Goroutines often need to:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>send data<\/li>\n\n\n\n<li>receive results<\/li>\n\n\n\n<li>signal completion<\/li>\n\n\n\n<li>coordinate work<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Channels provide a convenient way to do that.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">When?<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Use a channel when one goroutine needs to communicate with another goroutine.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">How?<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Create a channel:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>ch := make(chan string)<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Send into it:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>ch &lt;- \"hello\"<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Receive from it:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>message := &lt;-ch<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The arrow shows the direction the data travels.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Where?<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Channels commonly connect:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>producers and consumers<\/li>\n\n\n\n<li>background workers<\/li>\n\n\n\n<li>pipelines<\/li>\n\n\n\n<li>job queues<\/li>\n\n\n\n<li>result processors<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Complete Example<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>package main\n\nimport \"fmt\"\n\nfunc main() {\n\n\t\/\/ Create a channel that carries strings.\n\tmessageChannel := make(chan string)\n\n\t\/\/ Start a goroutine.\n\tgo func() {\n\n\t\t\/\/ Send a value into the channel.\n\t\tmessageChannel &lt;- \"Hello from goroutine\"\n\n\t}()\n\n\t\/\/ Receive the value from the channel.\n\tmessage := &lt;-messageChannel\n\n\tfmt.Println(message)\n}<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Output:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Hello from goroutine<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">What Actually Happened?<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">First:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>messageChannel := make(chan string)<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">creates the pipe.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Then the goroutine sends:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>messageChannel &lt;- \"Hello from goroutine\"<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Then <code>main()<\/code> receives:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>message := &lt;-messageChannel<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Visually:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>flowchart LR\n    A&#91;Goroutine] --&gt;|\"Hello\"| B&#91;Channel]\n    B --&gt;|\"Hello\"| C&#91;main]<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">Buffered vs Unbuffered Channels<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">You will frequently hear these terms.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Unbuffered<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>ch := make(chan int)<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">There is no storage space.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The sender normally waits until someone receives the value.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Think:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Person A ----hands box directly----&gt; Person B<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Buffered<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>ch := make(chan int, 3)<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The channel can temporarily hold three values.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Think:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Person A ---&gt; Mailbox ---&gt; Person B<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The sender can leave messages in the mailbox until it becomes full.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Simple Difference<\/h2>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th>Unbuffered<\/th><th>Buffered<\/th><\/tr><\/thead><tbody><tr><td><code>make(chan int)<\/code><\/td><td><code>make(chan int, 3)<\/code><\/td><\/tr><tr><td>No storage<\/td><td>Has storage<\/td><\/tr><tr><td>Sender and receiver synchronize directly<\/td><td>Sender may continue until buffer is full<\/td><\/tr><tr><td>Good for coordination<\/td><td>Good for temporary queues<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Start with <strong>unbuffered channels<\/strong> while learning.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">3. Channel Direction<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Channels normally support both sending and receiving.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">But sometimes a function should only be allowed to do one thing.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">For example:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Producer \u2192 sends\n\nConsumer \u2192 receives<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">What?<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Go lets you declare channels as:<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Send-only:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>chan&lt;- int<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Receive-only:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>&lt;-chan int<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Why?<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">It makes your code safer and easier to understand.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">If a function should only produce data, there is no reason to allow it to receive data.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">When?<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Use channel direction when passing channels into functions.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Especially when creating:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>producers<\/li>\n\n\n\n<li>consumers<\/li>\n\n\n\n<li>pipelines<\/li>\n\n\n\n<li>workers<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">How?<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Send-only:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>func producer(ch chan&lt;- int)<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Receive-only:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>func consumer(ch &lt;-chan int)<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Where?<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Channel direction is especially useful in larger concurrent programs because it documents the intended data flow.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Complete Example<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>package main\n\nimport \"fmt\"\n\n\/\/ This function can ONLY send data.\nfunc producer(ch chan&lt;- int) {\n\n\tfor i := 1; i &lt;= 3; i++ {\n\t\tch &lt;- i\n\t}\n\n\t\/\/ Producer owns the sending side,\n\t\/\/ so it closes the channel when finished.\n\tclose(ch)\n}\n\n\/\/ This function can ONLY receive data.\nfunc consumer(ch &lt;-chan int) {\n\n\tfor number := range ch {\n\t\tfmt.Println(\"Received:\", number)\n\t}\n}\n\nfunc main() {\n\n\t\/\/ Normal two-way channel.\n\tnumbers := make(chan int)\n\n\t\/\/ Producer receives it as send-only.\n\tgo producer(numbers)\n\n\t\/\/ Consumer receives it as receive-only.\n\tconsumer(numbers)\n}<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Output:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Received: 1\nReceived: 2\nReceived: 3<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Mental Model<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>Producer\n   |\n   | send only\n   v\nChannel\n   |\n   | receive only\n   v\nConsumer<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The syntax can initially look strange.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Remember:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>chan&lt;- int<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Arrow points <strong>into<\/strong> channel:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>SEND<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">And:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>&lt;-chan int<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Arrow comes <strong>out of<\/strong> channel:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>RECEIVE<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">4. <code>select<\/code><\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Suppose you have two channels.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">You don&#8217;t know which one will receive data first.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">How do you wait for both?<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">You use:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>select<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">What?<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\"><code>select<\/code> waits for one of several channel operations to become ready.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">It looks similar to <code>switch<\/code>.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Why?<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Without <code>select<\/code>, managing several channels becomes difficult.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><code>select<\/code> lets your program say:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\">Give me whichever channel has data available first.<\/p>\n<\/blockquote>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">When?<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Use <code>select<\/code> when dealing with:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>multiple channels<\/li>\n\n\n\n<li>timeouts<\/li>\n\n\n\n<li>cancellation<\/li>\n\n\n\n<li>multiple concurrent operations<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">How?<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Basic structure:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>select {\n\ncase value := &lt;-channel1:\n\t\/\/ channel1 received something\n\ncase value := &lt;-channel2:\n\t\/\/ channel2 received something\n}<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Where?<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Very common in:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>network servers<\/li>\n\n\n\n<li>timeout handling<\/li>\n\n\n\n<li>background workers<\/li>\n\n\n\n<li>cancellation logic<\/li>\n\n\n\n<li>concurrent API requests<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Complete Example<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>package main\n\nimport (\n\t\"fmt\"\n\t\"time\"\n)\n\nfunc main() {\n\n\tchannel1 := make(chan string)\n\tchannel2 := make(chan string)\n\n\t\/\/ First goroutine.\n\tgo func() {\n\n\t\ttime.Sleep(500 * time.Millisecond)\n\n\t\tchannel1 &lt;- \"Message from channel 1\"\n\n\t}()\n\n\t\/\/ Second goroutine.\n\tgo func() {\n\n\t\ttime.Sleep(1 * time.Second)\n\n\t\tchannel2 &lt;- \"Message from channel 2\"\n\n\t}()\n\n\t\/\/ We expect 2 messages.\n\tfor i := 0; i &lt; 2; i++ {\n\n\t\tselect {\n\n\t\tcase message := &lt;-channel1:\n\t\t\tfmt.Println(message)\n\n\t\tcase message := &lt;-channel2:\n\t\t\tfmt.Println(message)\n\n\t\tcase &lt;-time.After(2 * time.Second):\n\t\t\tfmt.Println(\"Timeout\")\n\n\t\t}\n\t}\n}<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Output:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Message from channel 1\nMessage from channel 2<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">What Happened?<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Channel 1 becomes ready after:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>500 milliseconds<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Channel 2 becomes ready after:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>1 second<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\"><code>select<\/code> handles whichever becomes ready.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>flowchart LR\n    A&#91;Channel 1] --&gt; C&#91;select]\n    B&#91;Channel 2] --&gt; C\n    D&#91;Timeout] --&gt; C\n    C --&gt; E&#91;Handle whichever is ready]<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Important<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\"><code>select<\/code> does <strong>not<\/strong> mean:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>check channel 1\nthen\ncheck channel 2<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">It means:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>wait until one is ready<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">5. Worker Pool<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Now we start combining what we learned.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Imagine you have:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>100 jobs<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">You could create:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>100 goroutines<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">But sometimes you don&#8217;t want unlimited concurrency.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Instead you could create:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>3 workers<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">and let those three workers process all the jobs.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">That is a <strong>worker pool<\/strong>.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">What?<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">A worker pool is a fixed number of goroutines processing jobs from a shared channel.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Example:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>             Worker 1\n            \/\nJobs ---&gt; Worker 2\n            \\\n             Worker 3<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Why?<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Worker pools help control concurrency.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Instead of creating thousands of goroutines simultaneously, you choose how many workers should operate.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">When?<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Use worker pools when you have:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>many similar jobs<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">but want:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>limited concurrency<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Examples:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>processing files<\/li>\n\n\n\n<li>database operations<\/li>\n\n\n\n<li>API requests<\/li>\n\n\n\n<li>image processing<\/li>\n\n\n\n<li>queue consumers<\/li>\n\n\n\n<li>batch processing<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">How?<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Usually you need:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>jobs channel\n       \u2193\nmultiple worker goroutines\n       \u2193\nresults channel<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Where?<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Worker pools are extremely common in backend and distributed systems.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Complete Example<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>package main\n\nimport (\n\t\"fmt\"\n\t\"sync\"\n\t\"time\"\n)\n\n\/\/ Worker receives jobs and sends results.\nfunc worker(\n\tid int,\n\tjobs &lt;-chan int,\n\tresults chan&lt;- int,\n\twg *sync.WaitGroup,\n) {\n\n\tdefer wg.Done()\n\n\tfor job := range jobs {\n\n\t\tfmt.Printf(\n\t\t\t\"Worker %d processing job %d\\n\",\n\t\t\tid,\n\t\t\tjob,\n\t\t)\n\n\t\t\/\/ Simulate some work.\n\t\ttime.Sleep(200 * time.Millisecond)\n\n\t\t\/\/ Send result.\n\t\tresults &lt;- job * 2\n\t}\n}\n\nfunc main() {\n\n\tjobs := make(chan int)\n\n\tresults := make(chan int)\n\n\tvar wg sync.WaitGroup\n\n\t\/\/ Create 3 workers.\n\tfor workerID := 1; workerID &lt;= 3; workerID++ {\n\n\t\twg.Add(1)\n\n\t\tgo worker(\n\t\t\tworkerID,\n\t\t\tjobs,\n\t\t\tresults,\n\t\t\t&amp;wg,\n\t\t)\n\t}\n\n\t\/\/ Send jobs.\n\tgo func() {\n\n\t\tfor job := 1; job &lt;= 5; job++ {\n\t\t\tjobs &lt;- job\n\t\t}\n\n\t\t\/\/ No more jobs will be sent.\n\t\tclose(jobs)\n\n\t}()\n\n\t\/\/ Wait for workers and then\n\t\/\/ close the results channel.\n\tgo func() {\n\n\t\twg.Wait()\n\n\t\tclose(results)\n\n\t}()\n\n\t\/\/ Read results.\n\tfor result := range results {\n\t\tfmt.Println(\"Result:\", result)\n\t}\n}<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Possible output:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Worker 1 processing job 1\nWorker 2 processing job 2\nWorker 3 processing job 3\nResult: 2\nResult: 4\nResult: 6\nWorker 1 processing job 4\nWorker 2 processing job 5\nResult: 8\nResult: 10<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The exact worker order may change.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">That is normal.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Worker Pool Mental Model<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>flowchart LR\n    J&#91;Jobs Channel]\n\n    J --&gt; W1&#91;Worker 1]\n    J --&gt; W2&#91;Worker 2]\n    J --&gt; W3&#91;Worker 3]\n\n    W1 --&gt; R&#91;Results Channel]\n    W2 --&gt; R\n    W3 --&gt; R\n\n    R --&gt; M&#91;Main]<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The key idea is:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\"><strong>Many jobs, limited number of workers.<\/strong><\/p>\n<\/blockquote>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">6. Fan-out and Fan-in<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">This sounds complicated.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">It is actually a simple idea.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">Fan-out<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">One source of work is distributed between multiple workers.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>            Worker 1\nInput -----&lt;\n            Worker 2<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">That is:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\"><strong>Fan-out<\/strong><\/p>\n<\/blockquote>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">Fan-in<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Multiple result streams are combined into one result stream.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Worker 1 ----\\\n              ---&gt; Results\nWorker 2 ----\/<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">That is:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\"><strong>Fan-in<\/strong><\/p>\n<\/blockquote>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">What?<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Together:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Input\n  |\n  +------ Worker 1 -----\\\n  |                      \\\n  +------ Worker 2 -------&gt; Combined Output<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Why?<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">You can process data concurrently and then bring the results back together.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">When?<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Useful for processing pipelines where:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>work arrives<\/li>\n\n\n\n<li>multiple goroutines process it<\/li>\n\n\n\n<li>results need to be collected<\/li>\n<\/ol>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">How?<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Typical pattern:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Generator\n     \u2193\nmultiple processors\n     \u2193\nmerge\n     \u2193\nconsumer<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Where?<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Useful in:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>data pipelines<\/li>\n\n\n\n<li>batch processing<\/li>\n\n\n\n<li>stream processing<\/li>\n\n\n\n<li>file processing<\/li>\n\n\n\n<li>event processing<\/li>\n\n\n\n<li>search systems<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">Complete Example<\/h1>\n\n\n\n<pre class=\"wp-block-code\"><code>package main\n\nimport (\n\t\"fmt\"\n\t\"sync\"\n)\n\n\/\/ Generate numbers.\nfunc generator(numbers ...int) &lt;-chan int {\n\n\tout := make(chan int)\n\n\tgo func() {\n\n\t\tdefer close(out)\n\n\t\tfor _, number := range numbers {\n\t\t\tout &lt;- number\n\t\t}\n\n\t}()\n\n\treturn out\n}\n\n\/\/ Square numbers.\n\/\/\n\/\/ Multiple copies of this function\n\/\/ can read from the same input channel.\nfunc square(in &lt;-chan int) &lt;-chan int {\n\n\tout := make(chan int)\n\n\tgo func() {\n\n\t\tdefer close(out)\n\n\t\tfor number := range in {\n\t\t\tout &lt;- number * number\n\t\t}\n\n\t}()\n\n\treturn out\n}\n\n\/\/ Merge multiple channels into one channel.\nfunc merge(channels ...&lt;-chan int) &lt;-chan int {\n\n\tvar wg sync.WaitGroup\n\n\tout := make(chan int)\n\n\twg.Add(len(channels))\n\n\t\/\/ Copy values from each input\n\t\/\/ channel into the output channel.\n\tfor _, channel := range channels {\n\n\t\tgo func(ch &lt;-chan int) {\n\n\t\t\tdefer wg.Done()\n\n\t\t\tfor value := range ch {\n\t\t\t\tout &lt;- value\n\t\t\t}\n\n\t\t}(channel)\n\t}\n\n\t\/\/ Close output only after\n\t\/\/ all input channels finish.\n\tgo func() {\n\n\t\twg.Wait()\n\n\t\tclose(out)\n\n\t}()\n\n\treturn out\n}\n\nfunc main() {\n\n\t\/\/ Produce numbers.\n\tinput := generator(\n\t\t1,\n\t\t2,\n\t\t3,\n\t\t4,\n\t\t5,\n\t\t6,\n\t)\n\n\t\/\/ FAN-OUT:\n\t\/\/ Two goroutines read from the\n\t\/\/ same input channel.\n\tworker1 := square(input)\n\tworker2 := square(input)\n\n\t\/\/ FAN-IN:\n\t\/\/ Merge both result channels.\n\tresults := merge(\n\t\tworker1,\n\t\tworker2,\n\t)\n\n\tfor result := range results {\n\t\tfmt.Println(result)\n\t}\n}<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Possible output:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>1\n9\n16\n25\n36\n4<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The order may change.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">But every input number is processed once.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Visual Explanation<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>flowchart LR\n    A&#91;Generator]\n\n    A --&gt; B&#91;Square Worker 1]\n    A --&gt; C&#91;Square Worker 2]\n\n    B --&gt; D&#91;Merge]\n    C --&gt; D\n\n    D --&gt; E&#91;Main]<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The left side is:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>FAN-OUT<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">because one stream goes to multiple workers.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The right side is:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>FAN-IN<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">because multiple streams become one stream.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">Now Compare Everything<\/h1>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th>Concept<\/th><th>Main Purpose<\/th><th>Simplest Mental Model<\/th><th>Main Syntax<\/th><th>Needs Goroutines?<\/th><th>Needs Channels?<\/th><\/tr><\/thead><tbody><tr><td>Goroutine<\/td><td>Run work concurrently<\/td><td>Worker<\/td><td><code>go function()<\/code><\/td><td>It is the goroutine<\/td><td>No<\/td><\/tr><tr><td>Channel<\/td><td>Communicate between goroutines<\/td><td>Pipe<\/td><td><code>make(chan T)<\/code><\/td><td>Usually<\/td><td>Yes<\/td><\/tr><tr><td>Channel Direction<\/td><td>Restrict send\/receive<\/td><td>One-way pipe<\/td><td><code>chan&lt;- T<\/code>, <code>&lt;-chan T<\/code><\/td><td>Usually<\/td><td>Yes<\/td><\/tr><tr><td><code>select<\/code><\/td><td>Wait on multiple channel operations<\/td><td>Channel switchboard<\/td><td><code>select {}<\/code><\/td><td>Usually<\/td><td>Yes<\/td><\/tr><tr><td>Worker Pool<\/td><td>Limit number of concurrent workers<\/td><td>Team sharing jobs<\/td><td>Goroutines + channels<\/td><td>Yes<\/td><td>Usually<\/td><\/tr><tr><td>Fan-out \/ Fan-in<\/td><td>Split and merge concurrent work<\/td><td>Branch and merge<\/td><td>Goroutines + channels<\/td><td>Yes<\/td><td>Yes<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">The Most Important Differences<\/h1>\n\n\n\n<h2 class=\"wp-block-heading\">Goroutine vs Channel<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">A goroutine:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>does work<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">A channel:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>moves information<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Think:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Goroutine = Worker\n\nChannel = Communication pipe<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">Channel vs Channel Direction<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">A normal channel:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>chan int<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">can send and receive.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Send-only:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>chan&lt;- int<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Receive-only:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>&lt;-chan int<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">So channel direction is not another type of concurrency.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">It simply makes channel usage safer.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">Channel vs <code>select<\/code><\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">A channel handles communication.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Channel = communicate<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\"><code>select<\/code> handles multiple channel operations.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>select = choose whichever channel is ready<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">Worker Pool vs Goroutine<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">A single goroutine means:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>one concurrent worker<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">A worker pool means:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>a controlled group of concurrent workers<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">For example:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>1000 jobs\n\nbut only:\n\n5 workers<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">Worker Pool vs Fan-out \/ Fan-in<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">These are similar, which is why beginners often confuse them.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Worker Pool<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Main goal:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\"><strong>Control how many workers process jobs.<\/strong><\/p>\n<\/blockquote>\n\n\n\n<p class=\"wp-block-paragraph\">Example:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>100 jobs\n   \u2193\n3 workers\n   \u2193\nresults<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Fan-out \/ Fan-in<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Main goal:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\"><strong>Split processing across multiple paths and combine the outputs.<\/strong><\/p>\n<\/blockquote>\n\n\n\n<p class=\"wp-block-paragraph\">Example:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>                Worker 1\n               \/        \\\nInput --------&lt;          &gt;---- Combined Output\n               \\        \/\n                Worker 2<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">Quick Comparison<\/h1>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th>Worker Pool<\/th><th>Fan-out \/ Fan-in<\/th><\/tr><\/thead><tbody><tr><td>Focuses on worker count<\/td><td>Focuses on data flow<\/td><\/tr><tr><td>Usually one job queue<\/td><td>Usually pipeline-oriented<\/td><\/tr><tr><td>Workers share jobs<\/td><td>Work branches into processors<\/td><\/tr><tr><td>Controls concurrency<\/td><td>Parallelizes stages<\/td><\/tr><tr><td>Results may use one shared results channel<\/td><td>Results commonly need explicit merging<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">They can also exist together.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">A worker pool is effectively a common form of fan-out.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">But you should initially think of them as different ideas.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">How Everything Connects<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">You should learn these concepts in this exact order:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>1. Goroutine\n       \u2193\n2. Channel\n       \u2193\n3. Channel Direction\n       \u2193\n4. select\n       \u2193\n5. Worker Pool\n       \u2193\n6. Fan-out \/ Fan-in<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Why?<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Because each concept builds on the previous one.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">Final Mental Model<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Imagine a restaurant.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Goroutine<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">A chef.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Chef = Goroutine<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Multiple chefs can work concurrently.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Channel<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">The order counter.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Waiter ---&gt; Order Counter ---&gt; Chef<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The counter allows information to move between people.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Channel Direction<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Maybe one counter is:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Orders IN only<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">while another is:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Food OUT only<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">That restriction is channel direction.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\"><code>select<\/code><\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">A chef watches several order counters:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Counter A\nCounter B\nCounter C<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The chef takes whichever order becomes available first.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">That is <code>select<\/code>.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Worker Pool<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Instead of hiring one chef for every order:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>100 orders\n100 chefs<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">you hire:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>100 orders\n   \u2193\n5 chefs<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Those five chefs keep taking orders.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">That is a worker pool.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Fan-out<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Orders are distributed between several chefs:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>             Chef 1\nOrders ----&gt; Chef 2\n             Chef 3<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Fan-in<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Finished food comes back to one serving counter:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Chef 1 ----\\\nChef 2 -----&gt; Serving Counter\nChef 3 ----\/<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">The Six Concepts in One Sentence Each<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Goroutine<\/strong><\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\">Run a function concurrently.<\/p>\n<\/blockquote>\n\n\n\n<pre class=\"wp-block-code\"><code>go function()<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Channel<\/strong><\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\">Send information between goroutines.<\/p>\n<\/blockquote>\n\n\n\n<pre class=\"wp-block-code\"><code>ch &lt;- value\nvalue := &lt;-ch<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Channel Direction<\/strong><\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\">Restrict a function to sending or receiving.<\/p>\n<\/blockquote>\n\n\n\n<pre class=\"wp-block-code\"><code>chan&lt;- int\n\n&lt;-chan int<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\"><strong><code>select<\/code><\/strong><\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\">Wait for whichever channel operation becomes ready.<\/p>\n<\/blockquote>\n\n\n\n<pre class=\"wp-block-code\"><code>select {\ncase value := &lt;-ch1:\ncase value := &lt;-ch2:\n}<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Worker Pool<\/strong><\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\">Let a fixed number of goroutines process many jobs.<\/p>\n<\/blockquote>\n\n\n\n<pre class=\"wp-block-code\"><code>Jobs \u2192 Workers \u2192 Results<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Fan-out \/ Fan-in<\/strong><\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\">Split work between multiple goroutines and merge their results.<\/p>\n<\/blockquote>\n\n\n\n<pre class=\"wp-block-code\"><code>          Worker\n         \/      \\\nInput --          -- Output\n         \\      \/\n          Worker<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">What You Should Master First<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Do <strong>not<\/strong> try to master all six at the same time.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Start by making these three feel completely natural:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>go function()\n\nch &lt;- value\n\nvalue := &lt;-ch<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Once those make sense, learn:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>chan&lt;- T\n&lt;-chan T<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Then:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>select<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Only after that should you spend significant time on:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Worker Pools\nFan-out\nFan-in<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">That progression makes Go concurrency much easier to understand.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">Final Cheat Sheet<\/h1>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th>If you want to&#8230;<\/th><th>Use<\/th><\/tr><\/thead><tbody><tr><td>Run something concurrently<\/td><td>Goroutine<\/td><\/tr><tr><td>Send data between goroutines<\/td><td>Channel<\/td><\/tr><tr><td>Make a function send-only<\/td><td><code>chan&lt;- T<\/code><\/td><\/tr><tr><td>Make a function receive-only<\/td><td><code>&lt;-chan T<\/code><\/td><\/tr><tr><td>Wait on several channels<\/td><td><code>select<\/code><\/td><\/tr><tr><td>Limit concurrent workers<\/td><td>Worker Pool<\/td><\/tr><tr><td>Split work across processors<\/td><td>Fan-out<\/td><\/tr><tr><td>Combine multiple result streams<\/td><td>Fan-in<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">The most important relationship to remember is:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Goroutines do the work.\n\nChannels connect the work.\n\nselect coordinates channels.\n\nWorker pools control the workers.\n\nFan-out distributes the work.\n\nFan-in combines the results.<\/code><\/pre>\n","protected":false},"excerpt":{"rendered":"<p>This tutorial covers: The goal is simple: One concept \u2192 one mental model \u2192 one complete example. Every example is independent. You can copy it into main.go&#8230; <\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-1088","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"_links":{"self":[{"href":"https:\/\/www.devopsschool.com\/tutorials\/wp-json\/wp\/v2\/posts\/1088","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.devopsschool.com\/tutorials\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.devopsschool.com\/tutorials\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.devopsschool.com\/tutorials\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.devopsschool.com\/tutorials\/wp-json\/wp\/v2\/comments?post=1088"}],"version-history":[{"count":1,"href":"https:\/\/www.devopsschool.com\/tutorials\/wp-json\/wp\/v2\/posts\/1088\/revisions"}],"predecessor-version":[{"id":1089,"href":"https:\/\/www.devopsschool.com\/tutorials\/wp-json\/wp\/v2\/posts\/1088\/revisions\/1089"}],"wp:attachment":[{"href":"https:\/\/www.devopsschool.com\/tutorials\/wp-json\/wp\/v2\/media?parent=1088"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.devopsschool.com\/tutorials\/wp-json\/wp\/v2\/categories?post=1088"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.devopsschool.com\/tutorials\/wp-json\/wp\/v2\/tags?post=1088"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}