---
title: "To Thread or Not to Thread: An In-Depth Look at Ruby’s Execution Models"
description: "Threaded servers such as Puma and thread-based Sidekiq are popular Ruby deployment choices because threads can increase throughput without a proportional increase in memory. The post compares process and thread models using a memory model that separates static application memory from per-request processing memory, then refines it with Copy on Write (CoW), where forked processes share pages until writes force copies. It explains why RSS can double-count shared pages, recommends PSS and Linux’s /proc/$PID/smaps_rollup for more meaningful measurements, and gives a production example in which about two-thirds of static memory is shared. The conclusion is metric-dependent: preload applications to improve CoW, prefer fewer larger containers when appropriate, consider Unicorn for reliable request timeouts, and start web workloads at two threads unless substantial I/O wait justifies more; job processors may benefit from higher counts."
---

# To Thread or Not to Thread: An In-Depth Look at Ruby’s Execution Models

[Shopify](https://yomu.fyi/company/shopify) · 2023-10-18 · May 31, 2022

**Type:** Explainer

## Summary

Threaded servers such as Puma and thread-based Sidekiq are popular Ruby deployment choices because threads can increase throughput without a proportional increase in memory. The post compares process and thread models using a memory model that separates static application memory from per-request processing memory, then refines it with Copy on Write (CoW), where forked processes share pages until writes force copies. It explains why RSS can double-count shared pages, recommends PSS and Linux’s /proc/$PID/smaps\_rollup for more meaningful measurements, and gives a production example in which about two-thirds of static memory is shared. The conclusion is metric-dependent: preload applications to improve CoW, prefer fewer larger containers when appropriate, consider Unicorn for reliable request timeouts, and start web workloads at two threads unless substantial I/O wait justifies more; job processors may benefit from higher counts.

## Context

Ruby applications increasingly use threaded web servers and job processors. The stated motivation is to understand the throughput, memory, latency, request-timeout, and Copy on Write trade-offs involved in choosing processes or threads and selecting a thread count.

## Approach / What changed

The post builds a simplified memory model for processes and threads, then adds Copy on Write behavior to explain shared and private memory. It compares RSS with PSS and Linux smaps\_rollup measurements, uses production memory figures to estimate sharing, and discusses preloading, container sizing, server selection, and thread-count guidance.

## Takeaways

- RSS can overstate memory usage for forked servers because shared pages are reported for each process; PSS and /proc/$PID/smaps\_rollup provide more useful views of actual ownership and sharing.
- Preloading the application before forking improves Copy on Write efficiency by allowing more static memory to remain shared; delayed writes and other runtime changes can reduce that benefit.
- For threaded web workloads, the guidance is to start with two threads unless the application spends more than half its time waiting on I/O, while job processors can benefit from higher thread counts because they are generally more I/O intensive.

**Tags:** [Architecture](https://yomu.fyi/topic/architecture), [Deployment](https://yomu.fyi/topic/deployment), [Performance](https://yomu.fyi/topic/performance), [Scalability](https://yomu.fyi/topic/scalability)

- Source: [Shopify](https://shopify.engineering/ruby-execution-models)
- Source URL: https://shopify.engineering/ruby-execution-models
- Ingested by Yomu: 2026-08-30T15:26:09.819Z

[Read original post](https://shopify.engineering/ruby-execution-models)
