concurrency

A simple Go Concurrency example

GO go1.21 ✅ Build Success
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 ---