#Concurrency

Concurrency in Go uses goroutines and channels to run tasks simultaneously with controlled coordination. These posts cover errgroup patterns for structured concurrency, GOMEMLIMIT tuning for containerised workloads, and the idiomatic Go approaches that prevent race conditions and resource leaks.

37 posts tagged with concurrency. ← All posts

#A2A (14)#ADK (8)#AG-UI (6)#AI (9)#AI Agents (311)#AI Architecture (10)#AI Cost (10)#AI Cost Optimization (8)#AI Engineering (201)#AI Evaluation (8)#AI Governance (29)#AI Red Teaming (9)#AI Research (9)#AI Safety (8)#AI Security (21)#AI in Production (12)#AML (3)#API Design (10)#API Security (8)#APIs (55)#AWS (17)#Accounting (9)#Agent Skills (3)#Agentic AI (24)#Agentic Commerce (12)#Agentic RAG (8)#Agents (4)#Amazon Bedrock (8)#Analytics (3)#Architecture (36)#Audit (3)#Authentication (11)#Authorization (3)#Automation (6)#Azure (11)#Azure AI Foundry (9)#Backend Engineering (310)#Benchmarks (3)#Best Practices (3)#BigQuery (6)#Business Finance (8)#Business Strategy (55)#C (8)#CI/CD (8)#Caching (10)#Capital Markets (14)#Card Payments (12)#Cards (13)#Career (24)#Checkpointing (4)#Claude Code (8)#Cloud (5)#Cloud Architecture (3)#Cloud Native (10)#Code Review (8)#Collaboration (5)#Communication (9)#Compliance (52)#Computer Networking (9)#Computer Science (32)#Computer Vision (5)#Concurrency (37)#Consulting (3)#Containers (10)#Context Engineering (10)#Cost Optimisation (5)#Credit (14)#Credit Risk (14)#CrewAI (8)#Crypto (12)#Cryptocurrency (12)#Cryptography (8)#Custody (9)#DSPy (8)#Data (13)#Data Engineering (12)#Data Structures (9)#Databases (37)#Deployment (3)#Design Patterns (10)#DevOps (16)#DevSecOps (11)#Developer Experience (5)#Developer Tools (5)#Distributed Systems (94)#Documentation (3)#Edge AI (8)#Embeddings (15)#Emotional Intelligence (8)#Energy (8)#Engineering (11)#Engineering Culture (3)#Engineering Practices (16)#Error Handling (4)#Evaluation (53)#Event-Driven Architecture (8)#FREE-AI (8)#FX (5)#Feedback (4)#FinOps (23)#FinTech (6)#Financial AI (14)#Financial Systems (129)#Fine-Tuning (11)#Fintech (131)#Flutter (8)#Foreign Exchange (5)#Forward Deployed Engineer (8)#Forward Deployed Engineering (8)#Fraud (10)#Function Tools (5)#Functional Programming (3)#Fundraising (8)#GCP (5)#Gemma (4)#Generative AI (3)#Git (8)#Go (220)#Go-to-Market (8)#Google ADK (36)#Governance (56)#Granite (6)#GraphQL (3)#Growth (3)#Guardrails (25)#HIPAA (3)#HTTP (3)#Harness Engineering (8)#Hiring (8)#Hugging Face (8)#Human-in-the-Loop (8)#IBM watsonx (8)#Identity (11)#Integration (3)#Intellectual Property (8)#Interfaces (3)#JavaScript (8)#KYC (11)#KYC and AML (12)#Kafka (10)#Kubernetes (17)#LLM (5)#LLM Inference (8)#LLM-as-Judge (3)#LLMs (135)#LangChain (8)#LangGraph (11)#Leadership (26)#Ledger (12)#Legal (8)#Lending (14)#LlamaIndex (8)#MCP (22)#MLOps (31)#Machine Learning (32)#Marketing (16)#Markets (4)#Memory (15)#Memory Management (5)#Metrics (6)#Microservices (3)#Microsoft Agent Framework (150)#Middleware (6)#Migration (9)#Monitoring (3)#Multi-Agent (10)#Multi-Agent AI (14)#Multi-Agent Systems (73)#Multimodal (3)#Multimodal AI (8)#NIM (5)#NVIDIA (8)#OAuth (3)#OWASP (7)#Observability (44)#On-Device AI (8)#Open Source (7)#OpenTelemetry (5)#Operating Systems (8)#Operations (10)#Opinion (6)#Orchestration (10)#Organizational Design (8)#Payment Rails (16)#Payments (54)#People (8)#Performance (43)#Platform Engineering (9)#PreSales (8)#Privacy (5)#Privacy Engineering (3)#Process (4)#Product (27)#Product Management (8)#Production (8)#Programming (10)#Programming Languages (48)#Prompt Engineering (66)#Prompt Injection (6)#Protocol Buffers (3)#Protocols (9)#Providers (4)#Pydantic AI (8)#Python (142)#Quality (3)#RAG (58)#RBI (3)#REST (5)#Rails (16)#Reasoning Models (8)#Reconciliation (3)#RegTech (8)#Regulation (9)#Reliability (48)#Resilience (4)#Responsible AI (5)#Retrieval (3)#Risk (13)#Rust (32)#SRE (21)#Sales (9)#Scalability (3)#Security (81)#Security Engineering (8)#Self-Evolving Agents (16)#Sessions (3)#Settlement (9)#Soft Skills (8)#Software (3)#Software Architecture (36)#Software Engineering (144)#Spanner (4)#Startups (30)#Strands (8)#Streaming (28)#Structured Output (4)#Sustainability (8)#System Design (32)#Systems Programming (48)#Testing (49)#Tool Use (22)#Tooling (4)#Tools (3)#Trading (8)#Treasury (6)#Type System (3)#Type Systems (11)#TypeScript (8)#Vector Databases (21)#Vector Search (11)#Venture Capital (8)#Version Control (8)#Web Development (6)#Workflows (14)#gRPC (13)#smolagents (8)
Pratik Dhanave · ·7 min read

Channels and Demand Generation

You can have the right customer, sharp positioning, the right motion, and smart pricing — and still sell nothing, because no one knows you exist. Demand generation and channels are how you solve the awareness problem: getting the right people to discover you, and moving them from "never heard of it" toward "customer." For technical builders this is the least intuitive part of GTM, because it can't be reasoned out at a desk — it's found by testing where your customers actually are.

You can have the right customer, sharp positioning, the right motion, and smart pricing — and still sell nothing, because no one knows you exist. Demand generation and channels are how you solve the awareness problem, and it can't be reasoned out at a desk — it's found by testing where your customers actually are.

Pratik Dhanave · ·7 min read

Threads and Concurrency

A thread lets one process do several things at once — and the moment you have two threads touching the same memory, you've entered the hardest territory in all of programming: concurrency. Race conditions, deadlocks, and the need for synchronization are not exotic edge cases; they're the fundamental consequences of shared mutable state, and understanding them is what separates working concurrent code from code that fails mysteriously.

A thread lets one process do several things at once — and the moment two threads touch the same memory, you're in the hardest territory in programming: concurrency. Race conditions, deadlocks, and synchronization are the fundamental consequences of shared mutable state.

Pratik Dhanave · ·6 min read

MVCC and Concurrency Control

The reason a long analytics query doesn't block every writer in your database — and vice versa — is a single elegant idea: never overwrite data, keep multiple versions, and give each transaction a consistent snapshot in time. MVCC is how nearly every modern database delivers isolation without readers and writers fighting over locks.

The reason a long analytics query doesn't block every writer — and vice versa — is a single elegant idea: never overwrite data, keep multiple versions, and give each transaction a consistent snapshot in time. That's MVCC.

Pratik Dhanave · ·7 min read

What an Operating System Does

You write applications that run on top of an operating system every day, and mostly you can ignore it — until a performance mystery, a concurrency bug, or a resource limit forces you to understand what's underneath. The OS is doing two jobs for you constantly: managing the hardware's finite resources, and giving you clean abstractions over messy reality. Understanding those two jobs is understanding the machine your code actually runs on.

You write applications on top of an OS every day and mostly ignore it — until a performance mystery, concurrency bug, or resource limit forces you to understand it. The OS does two jobs: managing finite hardware, and abstracting messy reality. Understanding them is understanding the machine your code runs on.

Pratik Dhanave · ·7 min read

TLS: Where It All Comes Together

TLS is the protocol securing nearly every connection you make, and it's not a single cryptographic trick — it's the whole toolkit orchestrated into one handshake. Key exchange, certificates, signatures, and authenticated encryption each solve one sub-problem, and TLS composes them so that two parties who've never met can establish a private, tamper-proof, authenticated channel over a hostile network. Understanding the handshake is understanding how every earlier piece fits.

TLS secures nearly every connection you make, and it's not a single trick — it's the whole toolkit orchestrated into one handshake. Key exchange, certificates, signatures, and AEAD each solve one sub-problem, and TLS composes them into a private, authenticated channel over a hostile network.

Pratik Dhanave · ·6 min read

Why Rust?

Rust makes a promise that sounds impossible: memory safety without a garbage collector, and fearless concurrency without data races — all checked at compile time, with no runtime cost. The price is a compiler that argues with you until your program is correct. Understanding that bargain is the key to understanding why Rust exists and why people love it.

Rust makes a promise that sounds impossible: memory safety without a garbage collector, and fearless concurrency without data races — all checked at compile time, with no runtime cost. The price is a compiler that argues with you until your program is correct.

Pratik Dhanave · ·7 min read

Public-Key Cryptography

Symmetric encryption has a chicken-and-egg problem: to share a secret key securely, you seem to need a secure channel — which is what you were trying to build. Public-key cryptography is the astonishing idea that broke that loop: two mathematically-linked keys where knowing the public one doesn't reveal the private one. It's the foundation of key exchange, digital signatures, and essentially all secure communication over the open internet.

Symmetric encryption has a chicken-and-egg problem: sharing a secret key securely seems to need a secure channel. Public-key cryptography broke that loop — two mathematically-linked keys where the public one doesn't reveal the private. It's the foundation of key exchange and signatures.

Pratik Dhanave · ·13 min read

Red-Teaming Agents and RAG Systems

Why agents and retrieval turn a prompt injection into real-world action, how to red-team the highest-risk AI surface with benign canaries, and the least-privilege controls that shrink an attacker's blast radius.

The highest-risk modern surface: indirect injection via RAG/tools, tool abuse and excessive-agency exploitation, memory poisoning, multi-step attacks, and data-exfiltration channels — with a canary methodology and least privilege as the primary control.

Pratik Dhanave · ·14 min read

Inference Optimization

Making an LLM system faster and cheaper without touching the weights — the levers an application engineer actually controls, from streaming and caching to token trimming, model routing, and Go's real superpower: concurrency with a rate limiter.

Make LLM systems faster and cheaper without retraining: TTFT vs throughput, exact and semantic response caching, prompt caching, token reduction, model routing and cascades, and Go concurrency with a worker pool and rate limiter.

Pratik Dhanave · ·11 min read

The AI Security Landscape

Why LLM and agent applications open a genuinely new attack surface, the mental models to reason about it (OWASP Top 10 for LLM Applications, MITRE ATLAS, NIST AI RMF), and how to threat-model an AI system before you write a line of defensive code.

The opener to a series on securing LLM and agent systems: why AI apps have a new attack surface (instructions and data share one channel, tools grant real power), the OWASP Top 10 for LLM Applications, MITRE ATLAS, and how to threat-model an AI system.

Pratik Dhanave · ·14 min read

Advanced Workflows in Microsoft Agent Framework (Python)

Once you can wire a chain of executors, the graph earns its keep: concurrency, durable state, composition, and control — the patterns that turn a toy pipeline into a system that survives a crash.

Once you can wire a chain of executors, the graph earns its keep: concurrency, durable state, composition, and control — the patterns that turn a toy pipeline into a system that survives a crash.

Pratik Dhanave · ·6 min read

Typing Async Code and the Event Loop

Almost everything interesting in JavaScript is asynchronous — network calls, file reads, timers — and TypeScript types all of it through one generic: `Promise<T>`. But typing async code well means understanding the runtime it describes: the single-threaded event loop that makes non-blocking concurrency work. Types and runtime together are what let you write async code that's both correct and comprehensible.

Almost everything interesting in JavaScript is asynchronous, and TypeScript types all of it through one generic: Promise<T>. But typing async code well means understanding the runtime it describes — the single-threaded event loop that makes non-blocking concurrency work. Types and runtime together let you write async code that's correct and comprehensible.

Pratik Dhanave · ·7 min read

Hierarchical Supervision: Bounded Fan-Out, Ordered Fan-In, Fault Isolation

Lesson 6 of Harness Engineering in Go — a supervisor splits a task, fans out to concurrent workers behind a semaphore, and fans the results back in decomposition order, with each worker's failure (or panic) isolated to one result.

Lesson 6: bounded fan-out behind a semaphore, ordered fan-in via a pre-sized results slice, and per-worker fault isolation so one sub-agent panicking becomes one failed result instead of crashing the whole run.

Pratik Dhanave · ·11 min read

context: Cancellation, Deadlines, and Values

How Go's `context` package carries a cancellation signal, a deadline, and a small bag of request-scoped values across every API and goroutine boundary in a request — and the handful of rules that keep it from leaking or lying to you.

How Go's `context` package carries a cancellation signal, a deadline, and a small bag of request-scoped values across every API and goroutine boundary in a request — and the handful of rules that keep it...

Pratik Dhanave · ·13 min read

Atomics and the Go Memory Model

What a data race actually is, why it is undefined behavior rather than "just a wrong number," the happens-before rules that make concurrent code correct, and when `sync/atomic` is the right tool — and when it quietly is not.

What a data race actually is, why it is undefined behavior rather than "just a wrong number," the happens-before rules that make concurrent code correct, and when `sync/atomic` is the right tool — and when...

Pratik Dhanave · ·12 min read

The sync Package

When channels are the wrong tool — a working guide to shared memory and locks in Go: Mutex, RWMutex, WaitGroup, Once, Cond, Map, Pool, and the race detector that keeps you honest.

When channels are the wrong tool — a working guide to shared memory and locks in Go: Mutex, RWMutex, WaitGroup, Once, Cond, Map, Pool, and the race detector that keeps you honest.

Pratik Dhanave · ·3 min read

Orchestration Patterns — Microsoft Agent Framework in Go

The prebuilt orchestration builders in agent-framework-go — Sequential, Concurrent, Group Chat — plus wrapping a whole workflow as one agent.

The Sequential, Concurrent, and Group Chat orchestration builders in agent-framework-go, plus wrapping a whole workflow as one nestable agent.

Pratik Dhanave · ·12 min read

Channels and select

A working guide to Go's channels — unbuffered rendezvous vs buffered capacity, send/receive/close semantics, directional types in APIs, and how `select` multiplexes, times out, and disables cases with a nil channel.

A working guide to Go's channels — unbuffered rendezvous vs buffered capacity, send/receive/close semantics, directional types in APIs, and how `select` multiplexes, times out, and disables cases with a nil...

Pratik Dhanave · ·11 min read

Goroutines

What a goroutine actually is, why it is cheaper than a thread, and the one rule that separates working concurrent code from a program that quietly leaks itself to death: every goroutine you start must have a way to stop.

What a goroutine actually is, why it is cheaper than a thread, and the one rule that separates working concurrent code from a program that quietly leaks itself to death: every goroutine you start must have...

Pratik Dhanave · ·5 min read

State, Channels, and Reducers: How LangGraph Merges Updates

The one idea that makes everything else in LangGraph click: nodes don't pass messages, they update a shared state — and reducers decide how.

State is a typed dict of channels; each channel has an optional reducer. No reducer overwrites; a reducer (like add_messages or operator.add) combines. This is the single idea the rest of LangGraph is built on.

Pratik Dhanave · ·8 min read

Content Marketing and SEO

Of all the marketing disciplines, content marketing is the one engineers are most naturally suited to and least resistant to — because it isn't selling, it's teaching. You create something genuinely useful (an article, a guide, a tool), people find it when they need it, they learn to trust you, and some become customers. It's honest, it compounds, and it plays directly to a technical builder's strengths. For technical products, content marketing is often the single most effective and authentic marketing channel there is.

Of all the marketing disciplines, content marketing is the one engineers are most suited to and least resistant to — because it isn't selling, it's teaching. You create something genuinely useful, people find it when they need it, they learn to trust you. It's honest, it compounds, and for technical products it's often the most effective channel there is.

Pratik Dhanave · ·13 min read

Maps

How Go's built-in hash table really behaves — reference semantics, the nil-write panic, comma-ok, randomized iteration, why `&m[k]` is illegal, and the presizing and concurrency rules that separate correct map code from the code that bites you at 2 a.m.

How Go's built-in hash table really behaves — reference semantics, the nil-write panic, comma-ok, randomized iteration, why `&m[k]` is illegal, and the presizing and concurrency rules that separate correct...

Pratik Dhanave · ·3 min read

Orchestration Patterns — Microsoft Agent Framework in Python

Five prebuilt multi-agent shapes — Sequential, Concurrent, Group Chat, Handoff, Magentic — and when each beats hand-wiring a graph.

Sequential, Concurrent, Group Chat, Handoff, Magentic — the five prebuilt Microsoft Agent Framework orchestrations in Python and when each beats hand-wiring a graph.

Pratik Dhanave · ·2 min read

03 · Agent Workflow Patterns (sequential · concurrent · group chat)

This lesson teaches that orchestration is a property of the workflow, not the agents — the same three agents drop into three different built-in graph shapes.

The same three agents dropped into three built-in agentworkflow builders — sequential, concurrent, and round-robin group chat — showing orchestration is a property of the graph, not the agents.

Pratik Dhanave · ·8 min read

Async and Await

Threads are great for CPU-bound parallelism, but for handling thousands of network connections — each mostly waiting — spawning a thread per connection doesn't scale (recall the C10K problem from the OS series). Async/await is Rust's answer: write code that looks sequential but doesn't block a thread while waiting, letting a handful of threads handle enormous concurrency. Rust's async is powerful and zero-cost, with one distinctive twist — you bring your own runtime to actually run the async code.

For handling thousands of connections each mostly waiting, spawning a thread per connection doesn't scale. Async/await is Rust's answer: write code that looks sequential but doesn't block a thread while waiting. Rust's async is powerful and zero-cost, with one distinctive twist — you bring your own runtime.

Pratik Dhanave · ·8 min read

Message Passing with Channels

There are two great philosophies of concurrency: share memory (with locks, as the previous posts covered) or share nothing and communicate by passing messages. The message-passing school has a famous slogan — "do not communicate by sharing memory; instead, share memory by communicating" — and Rust supports it fully with channels. Instead of multiple threads carefully locking shared state, ownership of data is transferred from one thread to another through a channel, and Rust's ownership system makes that transfer clean and safe.

There are two great philosophies of concurrency: share memory (with locks) or share nothing and communicate by passing messages. Rust supports channels fully — and its ownership system makes message passing especially natural, because sending data through a channel *is* transferring ownership.

Pratik Dhanave · ·8 min read

Send and Sync: The Traits Behind Fearless Concurrency

How does the Rust compiler actually know that an `Arc<Mutex<T>>` is safe to share across threads but an `Rc<T>` isn't? The answer is two of the most elegant ideas in Rust: a pair of marker traits, `Send` and `Sync`, that encode thread-safety directly into the type system. They're rarely written by hand and often invisible, yet they're the machinery that makes fearless concurrency work — the compiler reasons about thread-safety by checking these traits, automatically, at compile time.

How does the compiler know an Arc<Mutex<T>> is safe to share across threads but an Rc<T> isn't? The answer is two elegant marker traits — Send and Sync — that encode thread-safety directly into the type system. Rarely written by hand and often invisible, they're the machinery that makes fearless concurrency work.

Pratik Dhanave · ·8 min read

Shared State: Arc and Mutex

Moving data into a single thread is safe but limiting — sometimes multiple threads genuinely need to share and mutate the same data. This is exactly where data races live in other languages, and where Rust's guarantees shine brightest. The answer is a pair of types, `Arc` and `Mutex`, that let you share mutable state across threads — and the compiler will refuse to compile code that shares it unsafely. You literally cannot forget the lock, because the data lives inside it.

Sometimes multiple threads genuinely need to share and mutate the same data — exactly where data races live in other languages, and where Rust's guarantees shine brightest. The answer is Arc and Mutex, which let you share mutable state across threads while the compiler refuses to compile unsafe sharing. You literally cannot forget the lock.

Pratik Dhanave · ·6 min read

Threads and Fearless Concurrency

Rust's boldest promise is "fearless concurrency" — the claim that you can write multithreaded code and have the compiler guarantee, at compile time, that you have no data races. Coming from languages where concurrency bugs are a dark art of subtle, intermittent horror, this sounds too good to be true. It isn't: the same ownership and borrowing rules that give Rust memory safety extend naturally to threads. This module explores concurrency, starting with the basics — spawning threads and moving data into them.

Rust's boldest promise is fearless concurrency — write multithreaded code and have the compiler guarantee, at compile time, that you have no data races. It isn't too good to be true: the same ownership and borrowing rules that give memory safety extend naturally to threads. Module 3 begins with the basics — spawning threads and moving data into them.

All posts on this site are written by Pratik Dhanave, an Agentic AI Architect with 7+ years building production distributed systems, multi-agent AI platforms, and cloud-native infrastructure. About the author → Each article includes working code, architecture diagrams, and references to the specific frameworks and standards discussed. Browse all posts or explore related topics using the tag cloud above.