Pattern 3: Parallelization¶
"Executing independent operations concurrently for better performance"
π Pattern Overview¶
Parallelization enables agents to execute multiple independent operations simultaneously rather than sequentially. This significantly improves performance for tasks that don't have dependencies.
π― Key Concepts¶
- Concurrent Execution: Run independent tasks simultaneously
- Dependency Management: Identify which tasks can run in parallel
- Result Aggregation: Collect and combine parallel results
- Error Isolation: Handle failures in parallel tasks independently
π How Codex Implements This¶
Location in Codebase¶
- Primary:
codex-rs/core/src/tools/parallel.rs
(lines 47-67) - Support:
codex-rs/core/src/codex.rs
(parallel tool calls)
Implementation Details¶
Codex's ToolCallRuntime
intelligently decides whether to execute tools in parallel or serially:
// From codex-rs/core/src/tools/parallel.rs
pub(crate) async fn handle_tool_call(
&mut self,
call: ToolCall,
output_index: usize,
output: &mut [ProcessedResponseItem],
) -> Result<(), CodexErr> {
let supports_parallel = self.router.tool_supports_parallel(&call.tool_name);
if supports_parallel {
// Launch task in background
self.spawn_parallel(call, output_index);
} else {
// Wait for pending parallel tasks to complete first
self.resolve_pending(output).await?;
// Execute serially
let response = self.dispatch_serial(call).await?;
output[output_index].response = Some(response);
}
Ok(())
}
Key Features¶
- Per-Tool Configuration: Each tool declares if it supports parallelization
- Async/Await: Uses Tokio for efficient concurrent execution
- Automatic Ordering: Serial tools wait for parallel tasks to complete
- Error Propagation: Parallel task failures propagate correctly
π‘ Real-World Example from Codex¶
When the LLM wants to read 3 files:
// Sequential (slow):
read("file1.py") // 10ms
read("file2.py") // 10ms
read("file3.py") // 10ms
// Total: 30ms
// Parallel (fast):
spawn(read("file1.py")) // }
spawn(read("file2.py")) // } All run concurrently
spawn(read("file3.py")) // }
await_all()
// Total: ~10ms
π Architecture Diagram¶
ββββββββββββββββββββββββββββββββββββββββββββββββ
β LLM Returns 3 Tool Calls β
β 1. read_file("a.py") β
β 2. read_file("b.py") β
β 3. shell("ls") β Must run serially β
βββββββββββββββββββββ¬βββββββββββββββββββββββββββ
β
βΌ
ββββββββββββββββββββββββ
β Tool Router β
β Check each tool β
ββββββββββββ¬ββββββββββββ
β
βββββββββββββββββ΄ββββββββββββββββββ
β β
βΌ βΌ
βββββββββββββββ ββββββββββββββββ
β Tools 1 & 2 β β Tool 3 β
β (parallel) β β (serial) β
ββββββββ¬βββββββ ββββββββ¬ββββββββ
β β
Spawn async Must wait
β β
βΌ βΌ
ββββββββββββββββββββββββββββ βββββββββββββββ
β ββββββββ ββββββββ β β β
β βTask 1β βTask 2β β β Task 3 β
β β a.py β β b.py β β β "ls" β
β βββββ¬βββ βββββ¬βββ β β β
β β β β β β
β βββββββββ¬ββββ β β β
β β β β β
β Wait for both β β Execute β
ββββββββββββββββ¬ββββββββββββ ββββββββ¬βββββββ
β β
ββββββββββββ¬ββββββββββββ
β
βΌ
ββββββββββββββββββββ
β Collect Results β
β Feed to LLM β
ββββββββββββββββββββ
π Python Examples¶
See the example files: - pattern_simple.py
: Basic parallel execution with asyncio - pattern_advanced.py
: Tool-aware parallelization - benchmarks.py
: Performance comparison
π Key Takeaways¶
- β Performance: 3x-10x speedup for I/O-bound operations
- β Scalability: Handles many concurrent operations efficiently
- β Smart Execution: Only parallelizes when safe
- β Error Handling: Isolated failures don't block other tasks
- β οΈ Complexity: More complex than sequential execution
π When to Use¶
- β Multiple independent file reads
- β Batch API calls to external services
- β Parallel data processing tasks
- β Multiple search queries
- β Tasks with dependencies (must be sequential)
- β Shared mutable state (needs synchronization)
β οΈ Common Pitfalls¶
1. Race Conditions¶
β BAD: Parallel writes to same file
β
GOOD: Parallel reads, or parallel writes to different files
2. Resource Exhaustion¶
3. Deadlocks¶
π Further Reading¶
- Codex Source:
codex-rs/core/src/tools/parallel.rs
- Async Rust: https://rust-lang.github.io/async-book/
- Tokio Guide: https://tokio.rs/tokio/tutorial
- Python asyncio: https://docs.python.org/3/library/asyncio.html
π See Also¶
- Pattern 1: Prompt Chaining - Parallel can be one step in chain
- Pattern 2: Routing - Router decides what runs parallel
- Pattern 5: Tool Use - Tools declare parallel capability
- Pattern 12: Exception Handling - Error handling in parallel tasks