Mermaid parallel processing diagrams: concurrent systems explained
Modern systems are parallel by default. A user clicks a button and triggers ten things at once: fetch user data, log analytics, load recommendations, check inventory—all happening in parallel. Traditional flowcharts force you to serialize this: "do A, then B, then C." But that's not how software actually works.
Mermaid's par blocks let you show parallel operations honestly—multiple sequences running concurrently, blocking points where they wait for each other, and race conditions where timing matters. This guide teaches you how to diagram parallelism clearly.
What parallel processing means
Parallelism = multiple things happening at the same time (or appearing to, in async systems).
Examples:
- A web request triggers three database queries in parallel
- A background job processes records while the UI responds to users
- A payment system validates fraud while charging the card while updating inventory
- A cache refreshes while users are still reading stale data
Showing this as "step 1, step 2, step 3" is misleading. A par block shows the truth: these steps overlap.
The par block syntax
In Mermaid sequence diagrams, a par block groups parallel operations:
sequenceDiagram
participant User
participant API
participant Analytics
participant Cache
User->>API: Click "buy now"
par Parallel processing
API->>Analytics: Log purchase event
and
API->>Cache: Invalidate product cache
end
API-->>User: 200 OK
Read it: When the user clicks, the API sends logs to Analytics AND invalidates the cache (in parallel), then responds to the user.
Key syntax:
par <description>— start a parallel blockand— separate parallel streamsend— close the block
Any operations inside the same par block run concurrently. Operations outside it run sequentially.
Real-world examples
Microservice payment processing
When a payment comes in, the system validates, charges, and updates inventory at the same time:
sequenceDiagram
participant Frontend
participant PaymentAPI
participant Validator
participant Processor
participant Inventory
Frontend->>PaymentAPI: POST /checkout { amount, items }
par Parallel validation and charge
PaymentAPI->>Validator: Validate card
Validator-->>PaymentAPI: Valid ✓
and
PaymentAPI->>Processor: Process charge
Processor-->>PaymentAPI: Charge OK
and
PaymentAPI->>Inventory: Check stock
Inventory-->>PaymentAPI: In stock ✓
end
PaymentAPI->>Inventory: Reserve stock
Inventory-->>PaymentAPI: Reserved
PaymentAPI-->>Frontend: 201 Order created
What this shows:
- Three parallel operations (validation, charge, inventory check) happen together
- After they're all done (the
parblock ends), a sequential operation (reserve stock) waits - Finally, the API responds to the frontend
Without the par block, readers might think: "Validate, then charge, then check." With it, they see: "All three at once, then reserve, then respond."
Web page loading (progressive rendering)
A page loads in parallel streams: HTML structure, images, CSS, JavaScript, third-party analytics:
sequenceDiagram
participant Browser
participant Server
participant CDN
participant Analytics
participant AdNetwork
Browser->>Server: GET /product/123
Server-->>Browser: HTML + critical CSS
par Loading assets
Browser->>CDN: GET style.css
CDN-->>Browser: CSS loaded
and
Browser->>CDN: GET product-image.jpg
CDN-->>Browser: Image loaded
and
Browser->>Analytics: Track pageview
Analytics-->>Browser: Tracked
and
Browser->>AdNetwork: Load banner ads
AdNetwork-->>Browser: Ads loaded (slower)
end
Browser->>Browser: Render page
Browser-->>Browser: Paint to screen
Insight: The page doesn't wait for ads to load before showing content. The par block shows that ads load in parallel with content, and the browser paints once critical assets are ready.
Database transaction with parallel reads
Read operations can happen in parallel; writes must be serial:
sequenceDiagram
participant App
participant DB
participant Cache
App->>DB: BEGIN TRANSACTION
par Parallel reads
App->>DB: SELECT users.balance WHERE id=1
DB-->>App: $100
and
App->>DB: SELECT daily_limit WHERE account=1
DB-->>App: $1000
and
App->>Cache: GET exchange_rate USD->EUR
Cache-->>App: 0.92
end
App->>App: Calculate: can_send = balance * rate < limit?
App->>DB: UPDATE users SET balance = balance - amount
DB-->>App: Updated
App->>DB: COMMIT
DB-->>App: OK
Why parallel matters: The three reads can query the database concurrently. They all complete faster than if they were serial (first read, then second, then third). Once all reads are done (par ends), the write happens.
Common patterns
Race condition: Who wins?
When two parallel operations both try to modify shared state, the result depends on timing. Show this with rect (a highlight box) or a note:
sequenceDiagram
participant User1
participant User2
participant Database
par User1 saves
User1->>Database: Update inventory: qty = 9
Database-->>User1: OK
and User2 saves
User2->>Database: Update inventory: qty = 8
Database-->>User2: OK
end
Note over Database: Who's right? Depends on which write happened last.
Database->>Database: Final value: qty = 8 (last write wins)
Better approach: Use locking or transactions to prevent the race:
sequenceDiagram
participant User1
participant User2
participant Database
User1->>Database: BEGIN TRANSACTION + LOCK
User1->>Database: SELECT qty (qty = 10)
User1->>Database: UPDATE qty = 9
par User2 waits
User2->>Database: BEGIN TRANSACTION + LOCK
Note over Database: User2 blocked, waiting for lock
and User1 continues
User1->>Database: COMMIT
Database-->>User1: OK
Database-->>User2: Lock acquired
end
User2->>Database: SELECT qty (qty = 9)
User2->>Database: UPDATE qty = 8
User2->>Database: COMMIT
Database-->>User2: OK
Timeout in parallel operations
Show what happens when one parallel task is too slow:
sequenceDiagram
participant Client
participant API
participant EmailService
participant Cache
Client->>API: POST /register
par Fast operations
API->>API: Generate user ID
API->>Cache: Store session
and Potentially slow operation
API->>EmailService: Send welcome email
Note over EmailService: (Can be slow)
end
Note over API: API responds immediately (doesn't wait for email)
API-->>Client: 201 User created
EmailService-->>EmailService: Email sent 5 seconds later (async)
Key insight: The API responds to the client before the email is sent. The par block ends, and the client gets their response. Email sending continues in the background.
Flowcharts don't show parallelism (clearly)
Flowcharts can show parallel paths using swimlanes, but they're less clear than sequence diagrams:
flowchart TD
subgraph API["API Service"]
A["Receive request"]
B["Validate"]
C["Update inventory"]
D["Return response"]
end
subgraph Analytics["Analytics Service"]
E["Log event"]
end
A --> B
B --> C
C --> D
A -.->|happens at same time| E
The dotted line suggests parallelism, but it's ambiguous. A sequence diagram with par is clearer.
Nested par blocks (sequential phases, each parallel)
When a process has multiple phases, each with parallel operations:
sequenceDiagram
participant Client
participant OrderService
participant PaymentService
participant InventoryService
participant NotificationService
Client->>OrderService: Create order
par Phase 1: Validation
OrderService->>PaymentService: Validate payment method
PaymentService-->>OrderService: Valid ✓
and
OrderService->>InventoryService: Check stock
InventoryService-->>OrderService: In stock ✓
end
par Phase 2: Charging and booking
OrderService->>PaymentService: Charge card
PaymentService-->>OrderService: Charged
and
OrderService->>InventoryService: Reserve stock
InventoryService-->>OrderService: Reserved
end
par Phase 3: Notifications (fire and forget)
OrderService->>NotificationService: Send confirmation
and
OrderService->>NotificationService: Send fulfillment request
end
OrderService-->>Client: 201 Order created
Structure:
- Phase 1: Validate payment AND check stock (parallel)
- Phase 2: Charge card AND reserve stock (parallel, but after Phase 1)
- Phase 3: Send notifications (parallel, but after Phase 2)
Each phase has internal parallelism; phases are sequential.
Comparison: par vs. alt vs. loop
| Block | Means | Use for |
|---|---|---|
| par | Parallel operations (concurrent) | Multiple things at once, race conditions |
| alt | Alternative paths (if-then-else) | Different outcomes based on conditions |
| loop | Repeated operations | Retries, polling, iterations |
A realistic scenario uses all three:
sequenceDiagram
participant Client
participant API
participant Cache
loop Retry up to 3 times
Client->>API: GET /data
alt Cache hit
API->>Cache: Check cache
Cache-->>API: Found
API-->>Client: 200 OK
break Found, exit loop
else Cache miss
par Parallel fetch and invalidate
API->>API: Query database
API-->>API: Result
and
API->>Cache: Invalidate old entry
Cache-->>API: OK
end
API-->>Client: 200 OK
break Success, exit loop
end
end
FAQ
Can flowcharts show parallelism?
Yes, with swimlanes. But it's less clear than a sequence diagram. Flowcharts are better for showing logic; sequence diagrams are better for showing timing and interactions.
What's the difference between par and simultaneous execution?
In a true multi-threaded system, par operations run truly simultaneously. In JavaScript/async, par operations might run on the same thread but interleave their work. For diagramming purposes, par means "no guaranteed order of completion"—they could be parallel or concurrent.
Does the order of "and" blocks matter?
No. All operations in a par block start at the same logical time. The and keyword just separates them visually. Internally, Mermaid renders them in the order listed, but semantically they're concurrent.
How do I show a dependency between parallel operations?
If operation B depends on operation A's result, they can't be truly parallel. Show them sequentially within the par block, or move B outside the par block to the next sequential step.
Can I have a par block inside an alt block?
Yes. You can nest any blocks:
sequenceDiagram
alt Condition
par Parallel ops under condition
A->>B: msg1
and
A->>C: msg2
end
end
Visualize concurrent systems in the MermaidCreator editor—sketch a microservice call with parallel API requests, then add a race condition to see how timing affects the outcome.
Related posts
Mermaid sequence diagram actors and lifelines
Master sequence diagram fundamentals — design interactions between services, APIs, and users with proper actor notation, lifelines, and message ordering.
Mermaid Subgraph Composition: Modular Complex Diagrams
Master nested subgraphs to organize large flowcharts and systems into reusable, readable modules—patterns for composition, hierarchy, and clarity.