<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Go on blog.iankulin.com</title><link>https://blog.iankulin.com/tags/go/</link><description>Recent content in Go on blog.iankulin.com</description><generator>Hugo</generator><language>en-AU</language><lastBuildDate>Tue, 12 Dec 2023 00:00:00 +0000</lastBuildDate><atom:link href="https://blog.iankulin.com/tags/go/index.xml" rel="self" type="application/rss+xml"/><item><title>Concurrency and channels in Go</title><link>https://blog.iankulin.com/concurrency-and-channels-in-go/</link><pubDate>Tue, 12 Dec 2023 00:00:00 +0000</pubDate><guid>https://blog.iankulin.com/concurrency-and-channels-in-go/</guid><description>&lt;img src="https://blog.iankulin.com/images/portal-logo.jpg" width="400" alt=""&gt;
&lt;p&gt;In the long ago times, I&amp;rsquo;d done several years of commercial programming before I ever had to worry about dealing with multiple things happening at the same time. Perhaps because of the rarity of this problem, doing it in traditional languages was not always elegant.&lt;/p&gt;
&lt;p&gt;In the modern world of everything happening on the network, and systems being build out of micro-services and APIs, the beginning programmer probably has to deal with this stuff in Programming 102. Luckily, modern languages have these considerations built in, and one language with a particular reputation for that is Go.&lt;/p&gt;
&lt;p&gt;In Go, we have &lt;em&gt;Goroutines&lt;/em&gt;. This is basically a way of calling a function in such a way that the function goes away and does it&amp;rsquo;s thing and the rest of the program doesn&amp;rsquo;t wait for it. To do this, you just pop a go directive in front of the function call. Consider this little program:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-go" data-lang="go"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#81a1c1;font-weight:bold"&gt;package&lt;/span&gt; main
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#81a1c1;font-weight:bold"&gt;import&lt;/span&gt; &lt;span style="color:#eceff4"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#a3be8c"&gt;&amp;#34;fmt&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#a3be8c"&gt;&amp;#34;math/rand&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#a3be8c"&gt;&amp;#34;time&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#eceff4"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#81a1c1;font-weight:bold"&gt;func&lt;/span&gt; &lt;span style="color:#88c0d0"&gt;waitAndReportWorker&lt;/span&gt;&lt;span style="color:#eceff4"&gt;()&lt;/span&gt; &lt;span style="color:#eceff4"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#81a1c1;font-weight:bold"&gt;for&lt;/span&gt; &lt;span style="color:#eceff4"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		sleepTime &lt;span style="color:#81a1c1"&gt;:=&lt;/span&gt; time&lt;span style="color:#eceff4"&gt;.&lt;/span&gt;&lt;span style="color:#88c0d0"&gt;Duration&lt;/span&gt;&lt;span style="color:#eceff4"&gt;(&lt;/span&gt;rand&lt;span style="color:#eceff4"&gt;.&lt;/span&gt;&lt;span style="color:#88c0d0"&gt;Intn&lt;/span&gt;&lt;span style="color:#eceff4"&gt;(&lt;/span&gt;&lt;span style="color:#b48ead"&gt;5&lt;/span&gt;&lt;span style="color:#eceff4"&gt;))&lt;/span&gt; &lt;span style="color:#81a1c1"&gt;*&lt;/span&gt; time&lt;span style="color:#eceff4"&gt;.&lt;/span&gt;Second
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		time&lt;span style="color:#eceff4"&gt;.&lt;/span&gt;&lt;span style="color:#88c0d0"&gt;Sleep&lt;/span&gt;&lt;span style="color:#eceff4"&gt;(&lt;/span&gt;sleepTime&lt;span style="color:#eceff4"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		fmt&lt;span style="color:#eceff4"&gt;.&lt;/span&gt;&lt;span style="color:#88c0d0"&gt;Printf&lt;/span&gt;&lt;span style="color:#eceff4"&gt;(&lt;/span&gt;&lt;span style="color:#a3be8c"&gt;&amp;#34;Worker slept for %s&amp;#34;&lt;/span&gt;&lt;span style="color:#eceff4"&gt;,&lt;/span&gt; sleepTime&lt;span style="color:#eceff4"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#eceff4"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#eceff4"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#81a1c1;font-weight:bold"&gt;func&lt;/span&gt; &lt;span style="color:#88c0d0"&gt;main&lt;/span&gt;&lt;span style="color:#eceff4"&gt;()&lt;/span&gt; &lt;span style="color:#eceff4"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#88c0d0"&gt;waitAndReportWorker&lt;/span&gt;&lt;span style="color:#eceff4"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#eceff4"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If we run this, main hands control over to the worker, which sleeps for a bit, prints a message then repeats (normally the worker would some, like, actual work; but for our demo purposes, having a little nap then reporting it it fine).&lt;/p&gt;
&lt;p&gt;&lt;a href="https://blog.iankulin.com/images/screen-shot-2023-11-23-at-8.34.12-pm.png"&gt;&lt;img src="https://blog.iankulin.com/images/screen-shot-2023-11-23-at-8.34.12-pm.png" width="1000" alt=""&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;We can convert it to a Goroutine, just by putting a go in front of the function call,&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-gdscript3" data-lang="gdscript3"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#81a1c1;font-weight:bold"&gt;func&lt;/span&gt; main&lt;span style="color:#eceff4"&gt;()&lt;/span&gt; &lt;span style="color:#eceff4"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	go waitAndReportWorker&lt;span style="color:#eceff4"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#eceff4"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Yay! Our first baby Goroutine. Sadly, this program will exit before the worker ever reports, so let&amp;rsquo;s add an infinite loop after we&amp;rsquo;ve launched the Goroutine. And we&amp;rsquo;ll do something in the loop so you can see that there things are happening concurrently in our program.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.iankulin.com/images/screen-shot-2023-11-23-at-8.46.11-pm.jpg" alt=""&gt;&lt;/p&gt;
&lt;h3 id="collisions"&gt;Collisions&lt;/h3&gt;
&lt;p&gt;In my confected example, it&amp;rsquo;s extremely unlikely that the message from the worker would collide with the message being printed in the main loop, but it&amp;rsquo;s possible. But if we scaled up to a worldwide networked system processing millions of something a minute, it becomes almost guaranteed. Maybe a couple of sentences being mangled in output to the terminal is no big drama, but if we were writing something to a memory location, a file, a heart surgery robot interface, a database etc it could be bad. So we need to avoid that.&lt;/p&gt;
&lt;p&gt;The way Go deals with this is with &lt;em&gt;channels&lt;/em&gt;. A channel is like a portal between the main program in sequential procedural program land, to the worker function. When the worker needs to interact in some way with the main program it passes something back through the portal, and Go deals with it to avoid the dreaded collision. The portal/channel works the other way as well - the main program can pass information through the portal to the worker function.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s have a look at the changes for this, then tease them out a little:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-gdscript3" data-lang="gdscript3"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#81a1c1;font-weight:bold"&gt;func&lt;/span&gt; waitAndReportWorker&lt;span style="color:#eceff4"&gt;(&lt;/span&gt;resultChan chan&lt;span style="color:#81a1c1"&gt;&amp;lt;-&lt;/span&gt; string&lt;span style="color:#eceff4"&gt;)&lt;/span&gt; &lt;span style="color:#eceff4"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#81a1c1;font-weight:bold"&gt;for&lt;/span&gt; &lt;span style="color:#eceff4"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		sleepTime &lt;span style="color:#eceff4"&gt;:&lt;/span&gt;&lt;span style="color:#81a1c1"&gt;=&lt;/span&gt; time&lt;span style="color:#81a1c1"&gt;.&lt;/span&gt;Duration&lt;span style="color:#eceff4"&gt;(&lt;/span&gt;rand&lt;span style="color:#81a1c1"&gt;.&lt;/span&gt;Intn&lt;span style="color:#eceff4"&gt;(&lt;/span&gt;&lt;span style="color:#b48ead"&gt;5&lt;/span&gt;&lt;span style="color:#eceff4"&gt;))&lt;/span&gt; &lt;span style="color:#81a1c1"&gt;*&lt;/span&gt; time&lt;span style="color:#81a1c1"&gt;.&lt;/span&gt;Second
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		time&lt;span style="color:#81a1c1"&gt;.&lt;/span&gt;Sleep&lt;span style="color:#eceff4"&gt;(&lt;/span&gt;sleepTime&lt;span style="color:#eceff4"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		resultChan &lt;span style="color:#81a1c1"&gt;&amp;lt;-&lt;/span&gt; fmt&lt;span style="color:#81a1c1"&gt;.&lt;/span&gt;Sprintf&lt;span style="color:#eceff4"&gt;(&lt;/span&gt;&lt;span style="color:#a3be8c"&gt;&amp;#34;&lt;/span&gt;&lt;span style="color:#ebcb8b"&gt;\n&lt;/span&gt;&lt;span style="color:#a3be8c"&gt;Worker slept for &lt;/span&gt;&lt;span style="color:#a3be8c"&gt;%s&lt;/span&gt;&lt;span style="color:#ebcb8b"&gt;\n&lt;/span&gt;&lt;span style="color:#a3be8c"&gt;&amp;#34;&lt;/span&gt;&lt;span style="color:#eceff4"&gt;,&lt;/span&gt; sleepTime&lt;span style="color:#eceff4"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#eceff4"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#eceff4"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#81a1c1;font-weight:bold"&gt;func&lt;/span&gt; main&lt;span style="color:#eceff4"&gt;()&lt;/span&gt; &lt;span style="color:#eceff4"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	resultChan &lt;span style="color:#eceff4"&gt;:&lt;/span&gt;&lt;span style="color:#81a1c1"&gt;=&lt;/span&gt; make&lt;span style="color:#eceff4"&gt;(&lt;/span&gt;chan string&lt;span style="color:#eceff4"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	go waitAndReportWorker&lt;span style="color:#eceff4"&gt;(&lt;/span&gt;resultChan&lt;span style="color:#eceff4"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#81a1c1;font-weight:bold"&gt;for&lt;/span&gt; &lt;span style="color:#eceff4"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		time&lt;span style="color:#81a1c1"&gt;.&lt;/span&gt;Sleep&lt;span style="color:#eceff4"&gt;(&lt;/span&gt;&lt;span style="color:#b48ead"&gt;250&lt;/span&gt; &lt;span style="color:#81a1c1"&gt;*&lt;/span&gt; time&lt;span style="color:#81a1c1"&gt;.&lt;/span&gt;Millisecond&lt;span style="color:#eceff4"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		fmt&lt;span style="color:#81a1c1"&gt;.&lt;/span&gt;Print&lt;span style="color:#eceff4"&gt;(&lt;/span&gt;&lt;span style="color:#a3be8c"&gt;&amp;#34;Nothing happening here &amp;#34;&lt;/span&gt;&lt;span style="color:#eceff4"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		result &lt;span style="color:#eceff4"&gt;:&lt;/span&gt;&lt;span style="color:#81a1c1"&gt;=&lt;/span&gt; &lt;span style="color:#81a1c1"&gt;&amp;lt;-&lt;/span&gt;resultChan
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		fmt&lt;span style="color:#81a1c1"&gt;.&lt;/span&gt;Println&lt;span style="color:#eceff4"&gt;(&lt;/span&gt;result&lt;span style="color:#eceff4"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#eceff4"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#eceff4"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;We create the channel with the &lt;code&gt;make&lt;/code&gt; function. The type for the channel is the type that we&amp;rsquo;re going to be passing through it. We pass the channel to our worker, where the function signature is:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;func waitAndReportWorker(resultChan chan&amp;lt;- string)&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;I like this little arrow, it&amp;rsquo;s showing which way the portal works. In this case its a portal (channel) for passing a string out of the worker back to the main program. Channels can go the other way, ie. to pass things into the worker, or they can be bi-directional, which I don&amp;rsquo;t really think I&amp;rsquo;d do - I&amp;rsquo;d just add another channel.&lt;/p&gt;
&lt;p&gt;In our worker, we stuff something into the channel with that same arrow:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;resultChan &amp;lt;- fmt.Sprintf(&amp;quot;\nWorker slept for %s\n&amp;quot;, sleepTime)&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;On the other end of our portal/channel (I wish they&amp;rsquo;d just called them portals - it&amp;rsquo;s no quirkier than the date formatting) in the main program we use another arrow to pull the value out:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;result := &amp;lt;-resultChan&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;If we run this code, it works, sort of.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.iankulin.com/images/screen-shot-2023-11-24-at-4.51.21-pm.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;If you look at the output at the bottom, you can see that extracting the string out of our channel is a blocking operation. The program is waiting there until it gets a value. That&amp;rsquo;s no use - we could have done that without mucking about with channels.&lt;/p&gt;
&lt;p&gt;Of course, there is a way around this. What we really want to to is check if there&amp;rsquo;s a value in the channel. If there is, process it, or if not, travel around our loop again. What we do is put the retrieval of the channel value as a case in a select block.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-gdscript3" data-lang="gdscript3"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#81a1c1;font-weight:bold"&gt;func&lt;/span&gt; main&lt;span style="color:#eceff4"&gt;()&lt;/span&gt; &lt;span style="color:#eceff4"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	resultChan &lt;span style="color:#eceff4"&gt;:&lt;/span&gt;&lt;span style="color:#81a1c1"&gt;=&lt;/span&gt; make&lt;span style="color:#eceff4"&gt;(&lt;/span&gt;chan string&lt;span style="color:#eceff4"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	go waitAndReportWorker&lt;span style="color:#eceff4"&gt;(&lt;/span&gt;resultChan&lt;span style="color:#eceff4"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#81a1c1;font-weight:bold"&gt;for&lt;/span&gt; &lt;span style="color:#eceff4"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		select &lt;span style="color:#eceff4"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#81a1c1;font-weight:bold"&gt;case&lt;/span&gt; result &lt;span style="color:#eceff4"&gt;:&lt;/span&gt;&lt;span style="color:#81a1c1"&gt;=&lt;/span&gt; &lt;span style="color:#81a1c1"&gt;&amp;lt;-&lt;/span&gt;resultChan&lt;span style="color:#eceff4"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			fmt&lt;span style="color:#81a1c1"&gt;.&lt;/span&gt;Println&lt;span style="color:#eceff4"&gt;(&lt;/span&gt;result&lt;span style="color:#eceff4"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		default&lt;span style="color:#eceff4"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			time&lt;span style="color:#81a1c1"&gt;.&lt;/span&gt;Sleep&lt;span style="color:#eceff4"&gt;(&lt;/span&gt;&lt;span style="color:#b48ead"&gt;250&lt;/span&gt; &lt;span style="color:#81a1c1"&gt;*&lt;/span&gt; time&lt;span style="color:#81a1c1"&gt;.&lt;/span&gt;Millisecond&lt;span style="color:#eceff4"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			fmt&lt;span style="color:#81a1c1"&gt;.&lt;/span&gt;Print&lt;span style="color:#eceff4"&gt;(&lt;/span&gt;&lt;span style="color:#a3be8c"&gt;&amp;#34;Nothing happening here &amp;#34;&lt;/span&gt;&lt;span style="color:#eceff4"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#eceff4"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#eceff4"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#eceff4"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This version of the program will work exactly how we want. The worker goroutine will execute independently of the main loop which runs permanently, but then when the worker goroutine has something to say, it uses the channel to pass it back to the main routine which deals with it at the first opportunity.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.iankulin.com/images/screen-shot-2023-11-24-at-6.04.35-pm.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;Even though this is all working how we&amp;rsquo;d like, there is bit of programming craftsmanship needed. You may already know &lt;code&gt;make()&lt;/code&gt; from using it for slices. When we&amp;rsquo;re using it we&amp;rsquo;re allocating some resources - so now we have the responsibility to release them.&lt;/p&gt;
&lt;p&gt;To release the channel we made above, we close it:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;close(resultChan)&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s add that for completeness. I&amp;rsquo;ll the time to exit my infinite loop. In practice You&amp;rsquo;ll have some other condition.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-go" data-lang="go"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#81a1c1;font-weight:bold"&gt;package&lt;/span&gt; main
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#81a1c1;font-weight:bold"&gt;import&lt;/span&gt; &lt;span style="color:#eceff4"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#a3be8c"&gt;&amp;#34;fmt&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#a3be8c"&gt;&amp;#34;math/rand&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#a3be8c"&gt;&amp;#34;time&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#eceff4"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#81a1c1;font-weight:bold"&gt;func&lt;/span&gt; &lt;span style="color:#88c0d0"&gt;waitAndReportWorker&lt;/span&gt;&lt;span style="color:#eceff4"&gt;(&lt;/span&gt;resultChan &lt;span style="color:#81a1c1;font-weight:bold"&gt;chan&lt;/span&gt;&lt;span style="color:#81a1c1"&gt;&amp;lt;-&lt;/span&gt; &lt;span style="color:#81a1c1"&gt;string&lt;/span&gt;&lt;span style="color:#eceff4"&gt;)&lt;/span&gt; &lt;span style="color:#eceff4"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#81a1c1;font-weight:bold"&gt;for&lt;/span&gt; &lt;span style="color:#eceff4"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		sleepTime &lt;span style="color:#81a1c1"&gt;:=&lt;/span&gt; time&lt;span style="color:#eceff4"&gt;.&lt;/span&gt;&lt;span style="color:#88c0d0"&gt;Duration&lt;/span&gt;&lt;span style="color:#eceff4"&gt;(&lt;/span&gt;rand&lt;span style="color:#eceff4"&gt;.&lt;/span&gt;&lt;span style="color:#88c0d0"&gt;Intn&lt;/span&gt;&lt;span style="color:#eceff4"&gt;(&lt;/span&gt;&lt;span style="color:#b48ead"&gt;5&lt;/span&gt;&lt;span style="color:#eceff4"&gt;))&lt;/span&gt; &lt;span style="color:#81a1c1"&gt;*&lt;/span&gt; time&lt;span style="color:#eceff4"&gt;.&lt;/span&gt;Second
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		time&lt;span style="color:#eceff4"&gt;.&lt;/span&gt;&lt;span style="color:#88c0d0"&gt;Sleep&lt;/span&gt;&lt;span style="color:#eceff4"&gt;(&lt;/span&gt;sleepTime&lt;span style="color:#eceff4"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		resultChan &lt;span style="color:#81a1c1"&gt;&amp;lt;-&lt;/span&gt; fmt&lt;span style="color:#eceff4"&gt;.&lt;/span&gt;&lt;span style="color:#88c0d0"&gt;Sprintf&lt;/span&gt;&lt;span style="color:#eceff4"&gt;(&lt;/span&gt;&lt;span style="color:#a3be8c"&gt;&amp;#34;\nWorker slept for %s\n&amp;#34;&lt;/span&gt;&lt;span style="color:#eceff4"&gt;,&lt;/span&gt; sleepTime&lt;span style="color:#eceff4"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#eceff4"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#eceff4"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#81a1c1;font-weight:bold"&gt;func&lt;/span&gt; &lt;span style="color:#88c0d0"&gt;main&lt;/span&gt;&lt;span style="color:#eceff4"&gt;()&lt;/span&gt; &lt;span style="color:#eceff4"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	resultChan &lt;span style="color:#81a1c1"&gt;:=&lt;/span&gt; &lt;span style="color:#81a1c1"&gt;make&lt;/span&gt;&lt;span style="color:#eceff4"&gt;(&lt;/span&gt;&lt;span style="color:#81a1c1;font-weight:bold"&gt;chan&lt;/span&gt; &lt;span style="color:#81a1c1"&gt;string&lt;/span&gt;&lt;span style="color:#eceff4"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#81a1c1;font-weight:bold"&gt;go&lt;/span&gt; &lt;span style="color:#88c0d0"&gt;waitAndReportWorker&lt;/span&gt;&lt;span style="color:#eceff4"&gt;(&lt;/span&gt;resultChan&lt;span style="color:#eceff4"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	startTime &lt;span style="color:#81a1c1"&gt;:=&lt;/span&gt; time&lt;span style="color:#eceff4"&gt;.&lt;/span&gt;&lt;span style="color:#88c0d0"&gt;Now&lt;/span&gt;&lt;span style="color:#eceff4"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#81a1c1;font-weight:bold"&gt;for&lt;/span&gt; &lt;span style="color:#eceff4"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#81a1c1;font-weight:bold"&gt;select&lt;/span&gt; &lt;span style="color:#eceff4"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#81a1c1;font-weight:bold"&gt;case&lt;/span&gt; result &lt;span style="color:#81a1c1"&gt;:=&lt;/span&gt; &lt;span style="color:#81a1c1"&gt;&amp;lt;-&lt;/span&gt;resultChan&lt;span style="color:#eceff4"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			fmt&lt;span style="color:#eceff4"&gt;.&lt;/span&gt;&lt;span style="color:#88c0d0"&gt;Println&lt;/span&gt;&lt;span style="color:#eceff4"&gt;(&lt;/span&gt;result&lt;span style="color:#eceff4"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#81a1c1;font-weight:bold"&gt;default&lt;/span&gt;&lt;span style="color:#eceff4"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			time&lt;span style="color:#eceff4"&gt;.&lt;/span&gt;&lt;span style="color:#88c0d0"&gt;Sleep&lt;/span&gt;&lt;span style="color:#eceff4"&gt;(&lt;/span&gt;&lt;span style="color:#b48ead"&gt;250&lt;/span&gt; &lt;span style="color:#81a1c1"&gt;*&lt;/span&gt; time&lt;span style="color:#eceff4"&gt;.&lt;/span&gt;Millisecond&lt;span style="color:#eceff4"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			fmt&lt;span style="color:#eceff4"&gt;.&lt;/span&gt;&lt;span style="color:#88c0d0"&gt;Print&lt;/span&gt;&lt;span style="color:#eceff4"&gt;(&lt;/span&gt;&lt;span style="color:#a3be8c"&gt;&amp;#34;Nothing happening here &amp;#34;&lt;/span&gt;&lt;span style="color:#eceff4"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#eceff4"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#81a1c1;font-weight:bold"&gt;if&lt;/span&gt; time&lt;span style="color:#eceff4"&gt;.&lt;/span&gt;&lt;span style="color:#88c0d0"&gt;Since&lt;/span&gt;&lt;span style="color:#eceff4"&gt;(&lt;/span&gt;startTime&lt;span style="color:#eceff4"&gt;).&lt;/span&gt;&lt;span style="color:#88c0d0"&gt;Seconds&lt;/span&gt;&lt;span style="color:#eceff4"&gt;()&lt;/span&gt; &lt;span style="color:#81a1c1"&gt;&amp;gt;=&lt;/span&gt; &lt;span style="color:#b48ead"&gt;10&lt;/span&gt; &lt;span style="color:#eceff4"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#81a1c1;font-weight:bold"&gt;break&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#eceff4"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#eceff4"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#81a1c1"&gt;close&lt;/span&gt;&lt;span style="color:#eceff4"&gt;(&lt;/span&gt;resultChan&lt;span style="color:#eceff4"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#eceff4"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This is pretty much the minimal set up you need to get going with concurrency with Go:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;the channel&lt;/li&gt;
&lt;li&gt;a goroutine&lt;/li&gt;
&lt;li&gt;a select in a loop&lt;/li&gt;
&lt;li&gt;some cleanup by closing the channel&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href="https://github.com/IanKulin/gochanneldemo"&gt;code on github&lt;/a&gt;&lt;/p&gt;</description></item><item><title>Date formatting in Go is quirky</title><link>https://blog.iankulin.com/date-formatting-in-go-is-quirky/</link><pubDate>Sat, 09 Dec 2023 00:00:00 +0000</pubDate><guid>https://blog.iankulin.com/date-formatting-in-go-is-quirky/</guid><description>&lt;p&gt;When I&amp;rsquo;m working in an unfamiliar language, I find its quicker to just ask ChatGPT to write samples of anything I need than to look it up. For instance, last night I needed to format a date in Go, and rather than Google that and pick one of the results and scroll past the ads to read something, I just asked ChatGPT to give me a code example of formatting a date I gave it to DDMMYYYY.&lt;/p&gt;
&lt;p&gt;The answer it spat out, was something like:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;dateString := currentTime.Format(&amp;quot;02012006&amp;quot;)&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Well, clearly it was hallucinating - it must have gotten confused between the date I gave it and the formatting string. Odd, but this flavour of things happens. It&amp;rsquo;s usually pretty good about fixing it if you point out an error, so I did that. It immediately apologised, agreed it had made an error, and gave me back the exact same thing. Poop, I guess it&amp;rsquo;s back to googling some docs then.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://go.dev/src/time/format.go"&gt;&lt;img src="https://blog.iankulin.com/images/gotimeformat.jpg" alt=""&gt;&lt;/a&gt;
&lt;em&gt;wtf&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Well there you go. 1/2 3:04:05pm 2006 - 1-2-3-4-5-6. That&amp;rsquo;s what&amp;rsquo;s up with Go time/date formatting. I probably would have thought that was cute when I was 20 something as well.&lt;/p&gt;</description></item><item><title>Simple API endpoint in Go</title><link>https://blog.iankulin.com/simple-api-endpoint-in-go/</link><pubDate>Wed, 27 Sep 2023 00:00:00 +0000</pubDate><guid>https://blog.iankulin.com/simple-api-endpoint-in-go/</guid><description>&lt;img src="https://blog.iankulin.com/images/gopher.png" width="219" alt=""&gt;
&lt;p&gt;I&amp;rsquo;d like a small, quick, low load endpoint on all my nodes and VM&amp;rsquo;s that exposes a text keyword indicating if that machine is okay for RAM and disk space. I&amp;rsquo;m currently using &lt;a href="https://blog.iankulin.com/tags/uptime-kuma/"&gt;Uptime Kuma&lt;/a&gt; to monitor if these machines are pingable, but I&amp;rsquo;d love a tiny bit more information from them so I&amp;rsquo;d get a &lt;a href="https://blog.iankulin.com/uptime-kuma-nfty/"&gt;Ntfy&lt;/a&gt; buzz on my phone if a machine is in trouble.&lt;/p&gt;
&lt;p&gt;I mentioned a couple of weeks ago that the benefit of doing it in C rather than Node.js was probably not worth the trouble, but then being a fickle developer, decided to write it in Go.&lt;/p&gt;
&lt;p&gt;This was a pretty sweet experience, it&amp;rsquo;s a nice language and the ecosystem is good. When writing such a small utility, you don&amp;rsquo;t really get a full appreciation for a language, but there is a couple of nice things going on - one I appreciated was that unused code - for example an import that&amp;rsquo;s not used, or a variable declared but not accessed is a compiler error and flagged by the intellisense as you type.&lt;/p&gt;
&lt;p&gt;In terms of the language as written, it&amp;rsquo;s fair to say C-like - there&amp;rsquo;s no weirdness like the formatting being semantic. It&amp;rsquo;s statically typed, but has good inference.&lt;/p&gt;
&lt;p&gt;The code is up on &lt;a href="https://github.com/IanKulin/vitals-glimpse"&gt;GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s hard-coded to port 10321 and the route is &lt;code&gt;/vitals.&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://blog.iankulin.com/images/screen-shot-2023-08-15-at-9.37.44-pm.png"&gt;&lt;img src="https://blog.iankulin.com/images/screen-shot-2023-08-15-at-9.37.44-pm.png" width="900" alt=""&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;You get back this JSON. In my Uptime Kuma system, I search for the keywords &lt;code&gt;mem_okay&lt;/code&gt; and &lt;code&gt;disk_okay&lt;/code&gt; - no need to parse the JSON, it&amp;rsquo;s just an on/off status check that will show up in red on the page if there&amp;rsquo;s trouble, and ping my phone using &lt;a href="https://blog.iankulin.com/uptime-kuma-nfty/"&gt;ntfy.sh&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In Uptime Kuma, there&amp;rsquo;s an option when setting up a new monitor for &lt;code&gt;Http(s) Keyword&lt;/code&gt;. How this works is that it will scrape that web address and look to see if a particular keyword exists. If the keyword is present on the page, that site is marked as up, if not, it&amp;rsquo;s marked as down.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://blog.iankulin.com/images/screen-shot-2023-08-15-at-7.47.44-pm.png"&gt;&lt;img src="https://blog.iankulin.com/images/screen-shot-2023-08-15-at-7.47.44-pm.png" width="900" alt=""&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Testing the memory threshold for the screenshot above was fun:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;stress-ng --vm-bytes $(awk &amp;#39;/MemAvailable/{printf &amp;#34;%d\n&amp;#34;, $2 * 0.9;}&amp;#39; &amp;lt; /proc/meminfo)k --vm-keep -m 1
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description></item></channel></rss>