SimPy Resource vs PriorityResource vs PreemptiveResource: Complete Guide to Resource Scheduling

SimPy provides three resource classes—Resource, PriorityResource, and PreemptiveResource—that differ in queue ordering and preemption capabilities, ranging from simple FIFO allocation to priority-based interruption of running processes.

The K-Dense-AI/scientific-agent-skills repository contains detailed reference implementations showing how each class manages process contention in discrete-event simulations. Understanding these differences is critical for accurately modeling real-world systems like CPU schedulers, emergency rooms, or manufacturing lines where task priority and preemption matter.

Core Differences Between SimPy Resource Types

SimPy's resource hierarchy adds progressive layers of scheduling control. Each class builds upon the previous one, starting from basic capacity limits to full preemption capabilities.

Resource: FIFO Semantics

The simpy.Resource class implements a simple semaphore-style resource where processes wait in a FIFO (first-come-first-served) queue. When a slot frees, the first waiting request in resource.queue is granted access. Once a process acquires the resource, it runs to completion or until voluntary release—there is no mechanism to interrupt an active holder.

Typical use: Modeling simple capacity constraints like gas pumps, database connection pools, or limited server instances where arrival order determines service sequence.

PriorityResource: Ordered Waiting Queue

simpy.PriorityResource extends Resource by replacing the FIFO queue with a priority heap (min-heap) ordered by a numeric priority argument. Lower values indicate higher priority. When a slot becomes available, the waiting request with the smallest priority value is served next.

Important limitation: This priority ordering only affects the waiting queue. A process currently holding the resource cannot be displaced; it runs uninterrupted until completion.

Typical use: VIP service lanes, emergency dispatch systems, or any scenario where waiting jobs have different importance levels but running jobs must complete.

PreemptiveResource: Interruptible Execution

simpy.PreemptiveResource extends PriorityResource with full preemption capabilities. When a higher-priority request arrives while a lower-priority process holds the resource, SimPy raises a simpy.Interrupt exception inside the active process's context. The preempted process exits its with block prematurely and can catch the exception to perform cleanup or resume later.

Implementation detail: According to the source in scientific-skills/simpy/references/process-interaction.md, the resource tracks currently holding processes and compares incoming request priorities against active holders to trigger interruptions.

Typical use: Real-time operating systems, CPU scheduling algorithms, or emergency room triage where critical tasks must immediately displace less urgent ones.

Implementation Details from Source Code

The scientific-skills/simpy/SKILL.md file summarizes these resource types in a comparative table format, while scientific-skills/simpy/references/resources.md contains the concrete implementation patterns.

Key architectural implementations:

  • Resource: Maintains resource.queue as a standard list processed in FIFO order
  • PriorityResource: Stores requests as tuples (priority, ...) in a heap structure, ensuring heapq always pops the lowest priority value first
  • PreemptiveResource: Checks incoming request priorities against active holders; if new_priority < active_priority, triggers simpy.Interrupt in the active process

Code Examples

Basic FIFO Resource

import simpy

env = simpy.Environment()
fifo_res = simpy.Resource(env, capacity=2)

def fifo_user(env, name):
    with fifo_res.request() as req:
        yield req
        print(f'{name} got the resource at {env.now}')
        yield env.timeout(5)
        print(f'{name} released the resource at {env.now}')

for i in range(3):
    env.process(fifo_user(env, f'FIFO-{i+1}'))
env.run()

Priority-Based Queue

import simpy

env = simpy.Environment()
prio_res = simpy.PriorityResource(env, capacity=1)

def prio_user(env, name, prio):
    with prio_res.request(priority=prio) as req:
        yield req
        print(f'{name} (prio={prio}) got the resource at {env.now}')
        yield env.timeout(5)

env.process(prio_user(env, 'Low‑prio', priority=10))
env.process(prio_user(env, 'High‑prio', priority=1))
env.run()

Preemptive Resource with Interrupt Handling

import simpy

env = simpy.Environment()
pre_res = simpy.PreemptiveResource(env, capacity=1)

def preemptive_user(env, name, prio):
    with pre_res.request(priority=prio) as req:
        try:
            yield req
            print(f'{name} (prio={prio}) acquired at {env.now}')
            yield env.timeout(10)      # Long job

            print(f'{name} finished at {env.now}')
        except simpy.Interrupt:
            print(f'{name} was pre‑empted at {env.now}')

env.process(preemptive_user(env, 'Low‑prio', priority=10))
env.process(preemptive_user(env, 'High‑prio', priority=1))
env.run()

When to Use Each Resource Type

Choose your resource class based on scheduling requirements:

  • Use Resource when you need simple capacity limiting without priority distinctions, such as modeling parking spaces or network bandwidth where first-come-first-served is realistic.

  • Use PriorityResource when tasks have different importance levels but should not be interrupted once started, such as hospital appointment scheduling or customer service tiers.

  • Use PreemptiveResource when critical tasks must immediately seize control from less urgent ones, such as real-time system interrupts or emergency medical triage where a critical patient displaces a stable one.

Summary

  • simpy.Resource provides FIFO access with no preemption; processes wait in arrival order and run to completion.
  • simpy.PriorityResource adds numeric priority to the waiting queue (lower value = higher priority) but does not interrupt active processes.
  • simpy.PreemptiveResource allows high-priority processes to interrupt low-priority holders via simpy.Interrupt exceptions.
  • All three classes share the same request() API, but PriorityResource and PreemptiveResource require the priority parameter.
  • Preempted processes must implement try/except simpy.Interrupt blocks to handle forced release gracefully.

Frequently Asked Questions

Can I change the priority of a waiting request after it has been submitted?

No, once a request is submitted to PriorityResource or PreemptiveResource, its priority is fixed in the heap. To change priority, you must cancel the existing request and submit a new one with the updated priority value.

What happens to a preempted process after it catches the Interrupt exception?

The preempted process exits the with resource.request() context, releasing the resource immediately. You can choose to retry the request later, terminate the process, or move it to another queue. The simulation continues based on your exception handling logic.

Does lower priority number mean higher or lower importance in SimPy?

Lower numeric values indicate higher priority. When using priority=1 versus priority=10, the request with priority 1 is considered more urgent and will be served first (or preempt the holder in PreemptiveResource).

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →