SimPy Python
Build reproducible discrete-event models whose clock, state transitions,
resource ownership, stopping rule, randomness, and observations represent the
real system rather than an accidental execution order.
Boundary and core objects
| Object |
Meaning |
Use it for |
Environment |
Scheduler, simulation clock, and event queue. |
One simulated world/replication. |
Event |
A future state that becomes triggered, processed, and optionally carries a value/failure. |
Synchronization and completion signals. |
Process |
An event wrapping a generator's lifecycle. |
Active entities that yield events. |
Timeout |
An event scheduled after simulated delay. |
Duration, not wall-clock sleep. |
Resource family |
Capacity tokens with queues. |
Exclusive/shared service and congestion. |
Container |
Homogeneous numeric level. |
Bulk inventory or fuel. |
Store |
Queued Python objects. |
Items, messages, or jobs with identity. |
A process function is a generator recipe; env.process(generator) registers it
and returns a Process event. yield event suspends simulated activity until
that event is processed. Calling a generator normally does not run the model.
Read the event and process model before mixing
callbacks, interrupts, conditions, or resource requests.
Ordered workflow
- Define the question, time unit, warm-up, horizon/stopping event, and measured
population before modeling implementation details.
- Separate domain state from the environment and random-number generator.
- Express every delay, wait, acquisition, release, failure, and cancellation as
an event transition.
- Select
Resource, Container, or Store from what is constrained—not by
superficial queue vocabulary.
- Record observations at defined transitions and with clear denominators.
- Run independent replications with controlled seeds; report uncertainty, not
one trace, when making stochastic claims.
- Test tiny deterministic timelines, contention, boundary times, interruption,
empty/full queues, and the stopping rule.
Decision rules
- Use
Resource when entities compete for interchangeable usage slots. Use a
with resource.request() as request: yield request block so ownership is
released on normal exit or interruption.
- Use
PriorityResource when waiting order follows an explicit priority. State
whether lower numeric values mean higher priority and define tie behavior.
- Use
PreemptiveResource only when an admitted user can be interrupted. Handle
simpy.Interrupt, remaining work, cleanup, and measurement bias.
- Use
Container for an aggregate quantity without item identity. Use Store
when objects and selection/filtering matter.
- Use
env.timeout(duration) for simulated time. Reject negative durations and
define whether zero delay is a legitimate same-time event.
- Use
env.any_of/event1 | event2 for races and all_of/& for barriers.
Inspect which events completed; a losing event may still need cancellation or
cleanup.
- Use
env.run(until=t) knowing events scheduled exactly at t are not a vague
“through time t” promise; write a boundary test for the chosen stopping form.
- Use
RealtimeEnvironment only when coupling to wall-clock behavior is an
explicit requirement. It is not a way to make simulation more accurate.
Read resources, time, and experiments for ownership,
queues, monitoring, randomness, and replication rules.
Canonical anchor
from collections.abc import Generator
from dataclasses import dataclass
import simpy
@dataclass(frozen=True)
class Visit:
customer: int
queued_at: float
started_at: float
finished_at: float
def customer(
env: simpy.Environment,
server: simpy.Resource,
customer_id: int,
service_time: float,
visits: list[Visit],
) -> Generator[simpy.Event, object, None]:
queued_at = env.now
with server.request() as request:
yield request
started_at = env.now
yield env.timeout(service_time)
visits.append(Visit(customer_id, queued_at, started_at, env.now))
The record captures state-transition times rather than sampling a mutable queue.
Arrival creation and random service draws belong outside this process so a test
can inject a deterministic schedule.
High-risk rules
- Do not mutate state “after a delay” without yielding that delay.
- Do not hold a resource while waiting for unrelated work unless the real entity
occupies it during that time.
- Do not manually release a context-managed request twice.
- Never share one mutable RNG implicitly across replications. Derive and record
per-replication seeds; common random numbers require an intentional design.
- Avoid global
random calls inside processes. Inject distributions or an RNG.
- A queue-length time average requires time weighting between changes; averaging
observations at arrivals answers a different question.
- Distinguish censored entities still in the system at the horizon from
completed entities. Do not silently discard them from denominators.
- Same-time events are ordered by scheduler rules and creation sequence. If the
answer must not depend on that order, encode priorities or redesign the event.
- An interrupted process must release resources and decide whether work resumes,
restarts, or is lost. Catching and ignoring the interrupt is not a model.
Version grounding and completion
The authoring baseline is official SimPy 4.1.2 stable documentation; the local
foundry has not yet executed the package. Check the installed version with
simpy.__version__ and inspect signatures before relying on exception fields, resource variants, or
environment behavior. Read verification.
Completion requires an explicit clock/stopping contract, correct resource
ownership, injected randomness, traceable observations, deterministic
micro-tests, stochastic replication checks where relevant, and evidence that
the result does not depend accidentally on global state or one seed.
References
- Event and process model
- Resources, time, and experiments
- Verification and grounding
1---2name: simpy-python3description: Use for writing, reviewing, debugging, testing, or analyzing Python SimPy discrete-event simulations. Trigger on Environment, Event, Process, timeout, Resource, PriorityResource, PreemptiveResource, Container, Store, queues, interrupts, simulation clocks, replications, or SimPy monitoring. Do not use for asyncio services, wall-clock schedulers, continuous ODE solvers, or Monte Carlo code without an event-process model.4---56# SimPy Python78Build reproducible discrete-event models whose clock, state transitions,9resource ownership, stopping rule, randomness, and observations represent the10real system rather than an accidental execution order.1112## Boundary and core objects1314| Object | Meaning | Use it for |15|---|---|---|16| `Environment` | Scheduler, simulation clock, and event queue. | One simulated world/replication. |17| `Event` | A future state that becomes triggered, processed, and optionally carries a value/failure. | Synchronization and completion signals. |18| `Process` | An event wrapping a generator's lifecycle. | Active entities that yield events. |19| `Timeout` | An event scheduled after simulated delay. | Duration, not wall-clock sleep. |20| `Resource` family | Capacity tokens with queues. | Exclusive/shared service and congestion. |21| `Container` | Homogeneous numeric level. | Bulk inventory or fuel. |22| `Store` | Queued Python objects. | Items, messages, or jobs with identity. |2324A process function is a generator recipe; `env.process(generator)` registers it25and returns a `Process` event. `yield event` suspends simulated activity until26that event is processed. Calling a generator normally does not run the model.27Read [the event and process model](references/event-model.md) before mixing28callbacks, interrupts, conditions, or resource requests.2930## Ordered workflow31321. Define the question, time unit, warm-up, horizon/stopping event, and measured33 population before modeling implementation details.342. Separate domain state from the environment and random-number generator.353. Express every delay, wait, acquisition, release, failure, and cancellation as36 an event transition.374. Select `Resource`, `Container`, or `Store` from what is constrained—not by38 superficial queue vocabulary.395. Record observations at defined transitions and with clear denominators.406. Run independent replications with controlled seeds; report uncertainty, not41 one trace, when making stochastic claims.427. Test tiny deterministic timelines, contention, boundary times, interruption,43 empty/full queues, and the stopping rule.4445## Decision rules4647- Use `Resource` when entities compete for interchangeable usage slots. Use a48 `with resource.request() as request: yield request` block so ownership is49 released on normal exit or interruption.50- Use `PriorityResource` when waiting order follows an explicit priority. State51 whether lower numeric values mean higher priority and define tie behavior.52- Use `PreemptiveResource` only when an admitted user can be interrupted. Handle53 `simpy.Interrupt`, remaining work, cleanup, and measurement bias.54- Use `Container` for an aggregate quantity without item identity. Use `Store`55 when objects and selection/filtering matter.56- Use `env.timeout(duration)` for simulated time. Reject negative durations and57 define whether zero delay is a legitimate same-time event.58- Use `env.any_of`/`event1 | event2` for races and `all_of`/`&` for barriers.59 Inspect which events completed; a losing event may still need cancellation or60 cleanup.61- Use `env.run(until=t)` knowing events scheduled exactly at `t` are not a vague62 “through time t” promise; write a boundary test for the chosen stopping form.63- Use `RealtimeEnvironment` only when coupling to wall-clock behavior is an64 explicit requirement. It is not a way to make simulation more accurate.6566Read [resources, time, and experiments](references/modeling.md) for ownership,67queues, monitoring, randomness, and replication rules.6869## Canonical anchor7071```python72from collections.abc import Generator73from dataclasses import dataclass7475import simpy767778@dataclass(frozen=True)79class Visit:80 customer: int81 queued_at: float82 started_at: float83 finished_at: float848586def customer(87 env: simpy.Environment,88 server: simpy.Resource,89 customer_id: int,90 service_time: float,91 visits: list[Visit],92) -> Generator[simpy.Event, object, None]:93 queued_at = env.now94 with server.request() as request:95 yield request96 started_at = env.now97 yield env.timeout(service_time)98 visits.append(Visit(customer_id, queued_at, started_at, env.now))99```100101The record captures state-transition times rather than sampling a mutable queue.102Arrival creation and random service draws belong outside this process so a test103can inject a deterministic schedule.104105## High-risk rules106107- Do not mutate state “after a delay” without yielding that delay.108- Do not hold a resource while waiting for unrelated work unless the real entity109 occupies it during that time.110- Do not manually release a context-managed request twice.111- Never share one mutable RNG implicitly across replications. Derive and record112 per-replication seeds; common random numbers require an intentional design.113- Avoid global `random` calls inside processes. Inject distributions or an RNG.114- A queue-length time average requires time weighting between changes; averaging115 observations at arrivals answers a different question.116- Distinguish censored entities still in the system at the horizon from117 completed entities. Do not silently discard them from denominators.118- Same-time events are ordered by scheduler rules and creation sequence. If the119 answer must not depend on that order, encode priorities or redesign the event.120- An interrupted process must release resources and decide whether work resumes,121 restarts, or is lost. Catching and ignoring the interrupt is not a model.122123## Version grounding and completion124125The authoring baseline is official SimPy 4.1.2 stable documentation; the local126foundry has not yet executed the package. Check the installed version with127`simpy.__version__` and inspect signatures before relying on exception fields, resource variants, or128environment behavior. Read [verification](references/verification.md).129130Completion requires an explicit clock/stopping contract, correct resource131ownership, injected randomness, traceable observations, deterministic132micro-tests, stochastic replication checks where relevant, and evidence that133the result does not depend accidentally on global state or one seed.134135## References136137- [Event and process model](references/event-model.md)138- [Resources, time, and experiments](references/modeling.md)139- [Verification and grounding](references/verification.md)