concurrency
A simple Go Concurrency example
concurrency
A simple Go Concurrency example
Details
- Language: go
- Environment: go1.21
- Tags: go, concurrency, example
Build Information
- Build Success: ✅ Yes
- Last Built: 2025-08-10T07:39:14.613861-07:00
- Total Duration: 6.874915042s
Execution Output
=== Basic Goroutine Demo ===
Received metrics: {Name:wlan0 BytesSent:1024 Timestamp:2025-08-10 14:39:16.68076619 +0000 UTC m=+0.104347234}
Received metrics: {Name:eth0 BytesSent:1024 Timestamp:2025-08-10 14:39:16.68080019 +0000 UTC m=+0.104381235}
=== Context Cancellation Demo ===
Request failed: context canceled
=== Error Handling Demo ===
Validation errors: [interface bad0: validation failed]
=== Real-World Monitoring Demo ===
Monitor received: {Name:wlan0 BytesSent:1024 Timestamp:2025-08-10 14:39:17.439490337 +0000 UTC m=+0.863071590}
Monitor received: {Name:eth0 BytesSent:1024 Timestamp:2025-08-10 14:39:17.439726132 +0000 UTC m=+0.863307384}
Monitor received: {Name:eth0 BytesSent:1024 Timestamp:2025-08-10 14:39:17.542644306 +0000 UTC m=+0.966225559}
Monitor received: {Name:wlan0 BytesSent:1024 Timestamp:2025-08-10 14:39:17.542775225 +0000 UTC m=+0.966356519}
Monitor received: {Name:eth0 BytesSent:1024 Timestamp:2025-08-10 14:39:17.639987538 +0000 UTC m=+1.063568874}
Monitor received: {Name:wlan0 BytesSent:1024 Timestamp:2025-08-10 14:39:17.640223124 +0000 UTC m=+1.063804376}
Monitor received: {Name:eth0 BytesSent:1024 Timestamp:2025-08-10 14:39:17.739272626 +0000 UTC m=+1.162853879}
Monitor received: {Name:wlan0 BytesSent:1024 Timestamp:2025-08-10 14:39:17.739513795 +0000 UTC m=+1.163095048}
Monitor received: {Name:eth0 BytesSent:1024 Timestamp:2025-08-10 14:39:17.844985168 +0000 UTC m=+1.268566170}
Monitor received: {Name:wlan0 BytesSent:1024 Timestamp:2025-08-10 14:39:17.845188379 +0000 UTC m=+1.268769423}
Testing Output
=== RUN TestMonitorInterfacesBasic
Received metrics: {Name:wlan0 BytesSent:1024 Timestamp:2025-08-10 14:39:20.065620681 +0000 UTC m=+0.101721702}
Received metrics: {Name:eth0 BytesSent:1024 Timestamp:2025-08-10 14:39:20.065666973 +0000 UTC m=+0.101767995}
--- PASS: TestMonitorInterfacesBasic (0.10s)
=== RUN TestFetchNetworkStats_Cancellation
--- PASS: TestFetchNetworkStats_Cancellation (0.00s)
=== RUN TestFetchNetworkStats_Success
--- PASS: TestFetchNetworkStats_Success (1.00s)
=== RUN TestValidateInterfaces
--- PASS: TestValidateInterfaces (0.05s)
=== RUN TestInterfaceMonitor
--- PASS: TestInterfaceMonitor (0.20s)
PASS
ok example 1.360s
Source Code
Makefile
build:
go mod init example 2>/dev/null || true
go mod tidy
go build -o main .
run:
./main
test:
go test -v ./...
clean:
rm -f main
go clean
autodoc.yaml
title: concurrency
description: A simple Go Concurrency example
tags:
- go
- concurrency
- example
environment: go1.21
created: 2025-08-09T17:30:24.002857-07:00
author: Jeff Shumate
go.mod
module example
go 1.21.13
main.go
package main
import (
"context"
"fmt"
"sync"
"time"
)
// Mock types for demonstration purposes
type InterfaceMetrics struct {
Name string
BytesSent int
Timestamp time.Time
}
type NetworkInterface struct {
Name string
}
// --- BEGIN BLOG EXAMPLE: BASIC GOROUTINE WITH CHANNEL ---
// Line 25-40
func monitorInterfacesBasic(ctx context.Context) {
interfaces := []NetworkInterface{
{Name: "eth0"},
{Name: "wlan0"},
}
results := make(chan InterfaceMetrics, len(interfaces))
var wg sync.WaitGroup
for _, iface := range interfaces {
wg.Add(1)
go func(name string) {
defer wg.Done()
// Simulate work
time.Sleep(100 * time.Millisecond)
metrics := InterfaceMetrics{
Name: name,
BytesSent: 1024,
Timestamp: time.Now(),
}
select {
case results <- metrics:
case <-ctx.Done():
return
}
}(iface.Name)
}
go func() {
wg.Wait()
close(results)
}()
for metrics := range results {
fmt.Printf("Received metrics: %+v\n", metrics)
}
}
// --- END BLOG EXAMPLE ---
// --- BEGIN BLOG EXAMPLE: CONTEXT CANCELLATION ---
// Line 65-85
func fetchNetworkStats(ctx context.Context, endpoint string) (string, error) {
reqCtx, cancel := context.WithTimeout(ctx, 2*time.Second)
defer cancel()
// Simulate network request
select {
case <-time.After(1 * time.Second):
return fmt.Sprintf("Stats from %s", endpoint), nil
case <-reqCtx.Done():
return "", reqCtx.Err()
}
}
func contextCancellationDemo() {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
go func() {
time.Sleep(500 * time.Millisecond)
cancel() // Cancel after 500ms
}()
result, err := fetchNetworkStats(ctx, "http://api.example.com/stats")
if err != nil {
fmt.Printf("Request failed: %v\n", err)
return
}
fmt.Printf("Result: %s\n", result)
}
// --- END BLOG EXAMPLE ---
// --- BEGIN BLOG EXAMPLE: ERROR HANDLING WITH WAITGROUP ---
// Line 105-130
func validateInterfaces(ctx context.Context, interfaces []string) []error {
var wg sync.WaitGroup
var mu sync.Mutex
var errors []error
for _, iface := range interfaces {
wg.Add(1)
go func(name string) {
defer wg.Done()
// Simulate validation
time.Sleep(50 * time.Millisecond)
if name == "bad0" {
mu.Lock()
errors = append(errors, fmt.Errorf("interface %s: validation failed", name))
mu.Unlock()
}
}(iface)
}
wg.Wait()
return errors
}
func errorHandlingDemo() {
interfaces := []string{"eth0", "wlan0", "bad0", "lo"}
errs := validateInterfaces(context.Background(), interfaces)
if len(errs) > 0 {
fmt.Printf("Validation errors: %v\n", errs)
}
}
// --- END BLOG EXAMPLE ---
// --- BEGIN BLOG EXAMPLE: REAL-WORLD MONITORING STRUCTURE ---
// Line 145-180
type InterfaceMonitor struct {
interfaces map[string]*NetworkInterface
metrics chan<- InterfaceMetrics
ctx context.Context
cancel context.CancelFunc
wg sync.WaitGroup
}
func NewInterfaceMonitor(metricsChan chan<- InterfaceMetrics) *InterfaceMonitor {
ctx, cancel := context.WithCancel(context.Background())
return &InterfaceMonitor{
interfaces: make(map[string]*NetworkInterface),
metrics: metricsChan,
ctx: ctx,
cancel: cancel,
}
}
func (m *InterfaceMonitor) Start() {
interfaces := []NetworkInterface{
{Name: "eth0"},
{Name: "wlan0"},
}
for _, iface := range interfaces {
m.interfaces[iface.Name] = &iface
m.wg.Add(1)
go func(name string) {
defer m.wg.Done()
m.monitorInterface(name)
}(iface.Name)
}
}
func (m *InterfaceMonitor) monitorInterface(name string) {
ticker := time.NewTicker(100 * time.Millisecond)
defer ticker.Stop()
for {
select {
case <-ticker.C:
metrics := InterfaceMetrics{
Name: name,
BytesSent: 1024,
Timestamp: time.Now(),
}
select {
case m.metrics <- metrics:
case <-m.ctx.Done():
return
}
case <-m.ctx.Done():
return
}
}
}
func (m *InterfaceMonitor) Stop() {
m.cancel()
m.wg.Wait()
}
func realWorldDemo() {
metricsChan := make(chan InterfaceMetrics, 10)
monitor := NewInterfaceMonitor(metricsChan)
go monitor.Start()
// Collect metrics for 500ms
go func() {
time.Sleep(500 * time.Millisecond)
monitor.Stop()
close(metricsChan)
}()
for metrics := range metricsChan {
fmt.Printf("Monitor received: %+v\n", metrics)
}
}
// --- END BLOG EXAMPLE ---
func main() {
fmt.Println("=== Basic Goroutine Demo ===")
ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)
defer cancel()
monitorInterfacesBasic(ctx)
time.Sleep(100 * time.Millisecond)
fmt.Println("\n=== Context Cancellation Demo ===")
contextCancellationDemo()
fmt.Println("\n=== Error Handling Demo ===")
errorHandlingDemo()
fmt.Println("\n=== Real-World Monitoring Demo ===")
realWorldDemo()
}
main_test.go
package main
import (
"context"
"sync"
"testing"
"time"
)
// --- BEGIN BLOG EXAMPLE: GOROUTINE TEST ---
// Line 10-25
func TestMonitorInterfacesBasic(t *testing.T) {
ctx, cancel := context.WithTimeout(context.Background(), 500*time.Millisecond)
defer cancel()
// We'll capture output instead of printing
var wg sync.WaitGroup
wg.Add(1)
go func() {
defer wg.Done()
monitorInterfacesBasic(ctx)
}()
done := make(chan struct{})
go func() {
wg.Wait()
close(done)
}()
select {
case <-done:
// Test passed
case <-time.After(400 * time.Millisecond):
t.Fatal("Test timed out")
}
}
// --- END BLOG EXAMPLE ---
// --- BEGIN BLOG EXAMPLE: CONTEXT CANCELLATION TEST ---
// Line 40-55
func TestFetchNetworkStats_Cancellation(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
cancel() // Immediately cancel
_, err := fetchNetworkStats(ctx, "http://api.example.com/stats")
if err == nil {
t.Fatal("Expected error from cancelled context")
}
}
func TestFetchNetworkStats_Success(t *testing.T) {
ctx := context.Background()
result, err := fetchNetworkStats(ctx, "http://api.example.com/stats")
if err != nil {
t.Fatalf("Unexpected error: %v", err)
}
if result == "" {
t.Fatal("Expected non-empty result")
}
}
// --- END BLOG EXAMPLE ---
// --- BEGIN BLOG EXAMPLE: ERROR HANDLING TEST ---
// Line 70-85
func TestValidateInterfaces(t *testing.T) {
interfaces := []string{"eth0", "wlan0", "bad0", "lo"}
errs := validateInterfaces(context.Background(), interfaces)
if len(errs) != 1 {
t.Fatalf("Expected 1 error, got %d", len(errs))
}
expectedErr := "interface bad0: validation failed"
if errs[0].Error() != expectedErr {
t.Fatalf("Expected error '%s', got '%s'", expectedErr, errs[0].Error())
}
}
// --- END BLOG EXAMPLE ---
// --- BEGIN BLOG EXAMPLE: REAL-WORLD MONITOR TEST ---
// Line 100-120
func TestInterfaceMonitor(t *testing.T) {
metricsChan := make(chan InterfaceMetrics, 10)
monitor := NewInterfaceMonitor(metricsChan)
monitor.Start()
// Let it run for a bit
time.Sleep(200 * time.Millisecond)
monitor.Stop()
// Should have received at least one metric
select {
case <-metricsChan:
// Good, we got metrics
default:
t.Fatal("Expected to receive metrics")
}
}
// --- END BLOG EXAMPLE ---