Skip to content

Performance

Roberto Cruz edited this page May 15, 2026 · 2 revisions

Performance & Scaling

Multi-Threading

Synthea uses a ThreadPoolExecutor internally. Pass --threads N or set generate.thread_pool_size in the config:

# Use 8 threads
uv run synthea -p 10000 --threads 8

# Equivalent via config
uv run synthea -p 10000 -c perf.properties
# perf.properties: generate.thread_pool_size = 8

Note: With more than 1 thread, generation order across patients is non-deterministic. For fully reproducible output, use --threads 1.

Reference Benchmarks

Tests run on an 8-core Linux machine with SSD storage, Python 3.11, UV:

Population Threads FHIR export Time
100 1 yes ~3 s
1 000 4 yes ~8 s
10 000 8 yes ~55 s
100 000 16 yes ~9 min

CSV export adds ~10–15% overhead. JSON export adds ~5%.

Memory Optimization

Each Person object holds the full clinical history in memory before export. For very large populations:

# Generate in batches of 100 to bound memory usage
from synthea import Generator, GeneratorOptions

opts = GeneratorOptions()
opts.threads = 1  # single thread keeps memory predictable

for batch_seed in range(0, 10_000, 100):
    opts.population_size = 100
    opts.seed = batch_seed
    Generator(opts).run()
    # Each batch writes files and frees memory

Profiling

# Profile a 100-patient run
uv run python -m cProfile -o profile.stats -m synthea -p 100

# Inspect results
uv run python -m pstats profile.stats
# In pstats: sort cumulative; stats 20

Compiled Dependencies

# Install with compiled C extensions where available
uv pip install --compile .

PyPy

# Run with PyPy for ~2× speedup on pure-Python code
uv venv --python pypy3.9
uv pip install -e .
uv run synthea -p 1000

Disk I/O

For large runs, FHIR output produces one file per patient — on spinning disks this becomes the bottleneck. Recommendations:

  • Use SSD or tmpfs for exporter.baseDirectory
  • Enable exporter.use_uuid_filenames = true to avoid filesystem overhead from long patient names
  • Disable unused export formats (exporter.csv.export = false)
  • If posting to a FHIR server, set exporter.fhir.server_url and disable file output to skip disk writes entirely

Distributed Generation

For populations > 1 million, run multiple Synthea processes with non-overlapping seed ranges:

# Process A: patients 0–499 999
uv run synthea -p 500000 -s 0 --threads 8 -o ./output-a &

# Process B: patients 500 000–999 999
uv run synthea -p 500000 -s 500000 --threads 8 -o ./output-b &

wait
# Merge: cat output-a/csv/patients.csv output-b/csv/patients.csv > patients.csv

Because each patient's output depends only on its seed and the module definitions, merging outputs from different seed ranges is safe.

Clone this wiki locally