SimPy Timeout Explained: Modelling Time Delays
The timeout is the most frequently used event in SimPy. It's how you say "wait for X time units."
The Basics
yield env.timeout(5)
That's it. The process pauses for 5 time units, then resumes.
What a Timeout Does
When you yield a timeout:
- SimPy creates an event scheduled for
now + delay - Your process suspends
- Time advances (possibly handling other events)
- At the scheduled time, your process resumes
No busy waiting. No real time passing. Just simulation time advancing.
Zero-Duration Timeouts
A timeout of 0 is valid and useful:
yield env.timeout(0)
This yields control to other processes scheduled at the same time, then immediately resumes. Useful for:
- Letting other processes at the same time run first
- Ordering events at the same time
- Avoiding infinite loops in tight cycles
Random Timeouts
Simulation rarely uses fixed times. Use random distributions:
import random
# Exponential interarrival time (mean = 5)
yield env.timeout(random.expovariate(1/5))
# Uniform between 2 and 8
yield env.timeout(random.uniform(2, 8))
# Normal distribution (mean=10, std=2)
yield env.timeout(max(0, random.gauss(10, 2))) # Ensure non-negative
# Triangular (min=5, mode=10, max=15)
yield env.timeout(random.triangular(5, 15, 10))
Using NumPy for Distributions
For more control:
import numpy as np
rng = np.random.default_rng(seed=42)
yield env.timeout(rng.exponential(5))
yield env.timeout(rng.gamma(2, 2))
yield env.timeout(rng.lognormal(1, 0.5))
NumPy gives you more distributions and better reproducibility with seeding.
Common Patterns
Service Time
Model how long something takes:
def serve_customer(env, customer):
print(f"Serving {customer} at {env.now}")
service_time = random.expovariate(1/5) # Mean 5 minutes
yield env.timeout(service_time)
print(f"Finished {customer} at {env.now}")
Interarrival Time
Model gaps between arrivals:
def customer_generator(env):
i = 0
while True:
interarrival = random.expovariate(1/3) # Mean 3 minutes
yield env.timeout(interarrival)
env.process(customer(env, f"C{i}"))
i += 1
Fixed Delay
Sometimes delays are constant:
yield env.timeout(5) # Always exactly 5
Use for setup times, fixed processing steps, or when randomness isn't needed.
Computed Delay
Calculate the delay dynamically:
def process(env, items):
for item in items:
process_time = item.size * 0.1 + item.complexity * 2
yield env.timeout(process_time)
Time Units
SimPy doesn't enforce units. You choose:
- Seconds
- Minutes
- Hours
- Days
- Whatever makes sense
Just be consistent. If arrivals are in minutes, service times should be too.
Document your choice:
# All times in minutes
MEAN_SERVICE_TIME = 5 # minutes
MEAN_INTERARRIVAL = 3 # minutes
Timeout Values
Timeouts must be non-negative:
yield env.timeout(5) # OK
yield env.timeout(0) # OK
yield env.timeout(-1) # Error!
If a random distribution might give negative values, protect against it:
yield env.timeout(max(0, random.gauss(5, 3)))
Getting the Timeout Value
Timeouts don't return meaningful values:
result = yield env.timeout(5)
print(result) # None
The value is always None. The purpose is the delay, not a return value.
Combining with Other Events
Timeouts combine with other events for deadlines:
# Wait for resource OR give up after 10 units
req = resource.request()
result = yield req | env.timeout(10)
if req in result:
# Got the resource
yield env.timeout(5) # Use it
resource.release(req)
else:
# Timed out
req.cancel()
Multiple Timeouts
You can create multiple timeouts and wait for all:
# Parallel delays
t1 = env.timeout(5)
t2 = env.timeout(10)
yield t1 & t2 # Completes at time 10
Or any:
t1 = env.timeout(5)
t2 = env.timeout(10)
yield t1 | t2 # Completes at time 5
Timeout vs Real Time
SimPy timeouts are simulation time, not real time.
import time
def process(env):
start_real = time.time()
yield env.timeout(1000000) # Million time units
end_real = time.time()
print(f"Real seconds: {end_real - start_real}") # Tiny!
Simulation time is free. You can simulate years in milliseconds.
RealtimeEnvironment
If you need real-time behaviour:
env = simpy.rt.RealtimeEnvironment(factor=1.0)
def process(env):
yield env.timeout(5) # Actually waits 5 seconds
factor controls speed: 0.5 = half speed, 2.0 = double speed.
Not Entirely Trivial
The timeout is simple in concept but subtle in practice:
- Choosing distributions matters
- Time units must be consistent
- Zero timeouts have specific uses
- Combining with other events enables patterns
Summary
Timeouts:
- Pause processes for simulation time
- Accept any non-negative duration
- Combine with random distributions
- Return None
- Are the foundation of time-based simulation
Master the timeout. Everything else builds on it.
Next Steps
Discover the Power of Simulation
Want to become a go-to expert in simulation with Python? The Complete Simulation Bootcamp will show you how simulation can transform your career and your projects.
Explore the Bootcamp