Python Communicating Sequential Processes — Core Concepts

What CSP actually means

Communicating Sequential Processes is a formal model for concurrency created by Tony Hoare in 1978. The core idea: programs are built from independent processes that interact exclusively through channels. Each process runs sequentially (no internal concurrency), but multiple processes run concurrently and coordinate through synchronized communication.

CSP became the theoretical foundation for Go’s goroutines and channels, Clojure’s core.async, and Rust’s crossbeam channels.

CSP vs actor model

Both avoid shared memory, but they differ in a key way:

CSPActor Model
Communication through named channelsCommunication through actor addresses
Synchronous by default (rendezvous)Asynchronous by default (mailboxes)
Channels are first-class (can be passed around)Actors are first-class entities
Focuses on the communication patternFocuses on the entities doing work

In CSP, channels are the stars. In the actor model, actors are. This distinction affects how you design systems — CSP tends to produce pipeline-style architectures, while actors tend to produce entity-style architectures.

The rendezvous principle

The defining feature of CSP is synchronous rendezvous: a send operation blocks until a receiver is ready, and a receive blocks until a sender is ready. Both sides must meet at the channel simultaneously.

This creates a natural form of back-pressure. If a producer is faster than a consumer, the producer automatically slows down because it’s blocked waiting for the consumer. No buffer overflow, no dropped messages.

CSP in Python

Python doesn’t have Go-style channels in the standard library, but you can implement CSP patterns:

Using queue.Queue(maxsize=0) for rendezvous channels:

Setting maxsize=0 in Python’s Queue actually means unlimited, so for true CSP rendezvous, use maxsize=1 and coordinate carefully, or use multiprocessing.Pipe for paired channels.

Using third-party libraries:

  • python-csp — direct CSP implementation with channels and process composition
  • aiocsp — async CSP channels for asyncio
  • trio — the trio.open_memory_channel() function creates bounded channels with CSP-style semantics

Select and multiplexing

In Go, select lets a process wait on multiple channels simultaneously, responding to whichever is ready first. Python equivalents:

  • asyncio.wait() with multiple coroutines
  • selectors module for I/O multiplexing
  • Trio’s approach with task groups and channels

This is how you build processes that can respond to multiple inputs without dedicated threads for each.

Common misconception

“CSP is just producer-consumer with queues.” Not quite. The synchronization guarantee is the difference. Regular queues buffer messages — the producer doesn’t know or care if the consumer has processed anything. CSP channels ensure both sides participate in each transfer, giving you stronger reasoning about program state.

Pipeline composition

CSP shines in pipeline architectures:

Reader → Parser → Transformer → Writer

Each stage is an independent process connected by channels. You can add stages, remove them, or swap implementations without touching other parts. The channel contracts are the API.

The one thing to remember: CSP gives you concurrency through synchronized channels rather than shared memory. The rendezvous model means communication is a coordination point, not just data transfer — making your concurrent programs easier to reason about.

pythonadvancedconcurrency

See Also

  • Python Actor Model Why treating each piece of your program like a person with their own mailbox makes concurrency way less scary.
  • Python Aiocache Caching aiocache remembers expensive answers so your async Python app doesn't waste time asking the same question twice.
  • Python Aiofiles Async Io aiofiles lets your async Python program read and write files without freezing — because normal file operations secretly block everything.
  • Python Aiohttp Understand Aiohttp through an everyday analogy so Python behavior feels intuitive, not random.
  • Python Anyio Portability AnyIO lets your async Python code work with any async library — write once, run on asyncio or Trio without changes.