Resources
Resources represent limited-capacity entities in your simulation that processes compete for. Examples include servers, machines, workers, parking spots, or network bandwidth.
Creating Resources
import { Simulation, Resource } from 'discrete-sim';
const sim = new Simulation();
const server = new Resource(sim, 2, { name: 'Server' });Parameters:
sim- The simulation instancecapacity- Number of concurrent users (e.g., 2 servers)options- Optional configurationname- Resource name for statistics and debugging
Using Resources
Basic Pattern
function* customer(id: number, server: Resource) {
// Request the resource
yield server.request();
// Use the resource
yield* timeout(5);
// Release the resource
server.release();
}Request and Release
yield resource.request() - Wait for the resource to become available. Returns a token that can be used for tracking.
resource.release() - Release the resource, making it available for the next waiting process.
function* process() {
const token = yield server.request();
console.log(`Acquired token ${token}`);
yield* timeout(10);
server.release();
console.log(`Released token ${token}`);
}Resource Properties
resource.capacity
The total capacity of the resource:
console.log(`Server capacity: ${server.capacity}`);resource.inUse
Current number of tokens in use:
console.log(`Currently serving: ${server.inUse}`);resource.available
Number of available tokens:
console.log(`Available servers: ${server.available}`);resource.queueLength
Number of processes waiting for the resource:
console.log(`Waiting in queue: ${server.queueLength}`);Resource Statistics
Resources automatically track statistics when given a name:
const server = new Resource(sim, 2, { name: 'Server' });
// After simulation runs
const stats = sim.statistics;
// Utilization (0-1)
console.log(stats.getAverage('Server:utilization'));
// Average queue length
console.log(stats.getAverage('Server:queue-length'));
// Average wait time
console.log(stats.getAverage('Server:wait-time'));Built-in Metrics
For a resource named "Server", the following metrics are automatically tracked:
Server:utilization- Fraction of capacity in use (time-weighted)Server:queue-length- Number of processes waiting (time-weighted)Server:wait-time- Time processes spend waiting (per request)
Examples
Single Server Queue
import { Simulation, Resource, timeout } from 'discrete-sim';
function* customer(id: number, server: Resource) {
const arrivalTime = sim.now;
console.log(`Customer ${id} arrives at ${arrivalTime}`);
yield server.request();
const waitTime = sim.now - arrivalTime;
console.log(`Customer ${id} waited ${waitTime}, starts service at ${sim.now}`);
yield* timeout(5);
server.release();
console.log(`Customer ${id} leaves at ${sim.now}`);
}
const sim = new Simulation();
const server = new Resource(sim, 1, { name: 'Server' });
// Customers arrive at times 0, 2, 4
for (let i = 0; i < 3; i++) {
sim.schedule(i * 2, () => {
sim.process(() => customer(i, server));
});
}
sim.run();
// Check statistics
console.log(`Average utilization: ${sim.statistics.getAverage('Server:utilization')}`);
console.log(`Average queue length: ${sim.statistics.getAverage('Server:queue-length')}`);
console.log(`Average wait time: ${sim.statistics.getAverage('Server:wait-time')}`);Multi-Resource System
Processes can request multiple resources:
function* job(id: number, machine: Resource, operator: Resource) {
console.log(`Job ${id} waiting for machine and operator`);
yield machine.request();
yield operator.request();
console.log(`Job ${id} processing at ${sim.now}`);
yield* timeout(10);
machine.release();
operator.release();
console.log(`Job ${id} complete at ${sim.now}`);
}
const sim = new Simulation();
const machine = new Resource(sim, 2, { name: 'Machine' });
const operator = new Resource(sim, 3, { name: 'Operator' });
for (let i = 0; i < 5; i++) {
sim.process(() => job(i, machine, operator));
}
sim.run();Priority Queue (Manual Implementation)
Resources use FIFO queuing by default. For priority queuing, manage requests manually:
interface PriorityRequest {
priority: number;
resolve: () => void;
}
class PriorityResource {
private queue: PriorityRequest[] = [];
private inUse = 0;
constructor(private capacity: number) {}
request(priority: number): Promise<void> {
if (this.inUse < this.capacity) {
this.inUse++;
return Promise.resolve();
}
return new Promise<void>((resolve) => {
this.queue.push({ priority, resolve });
this.queue.sort((a, b) => a.priority - b.priority);
});
}
release() {
if (this.queue.length > 0) {
const next = this.queue.shift()!;
next.resolve();
} else {
this.inUse--;
}
}
}Common Patterns
Resource Pools
Model interchangeable resources:
const workers = new Resource(sim, 5, { name: 'Workers' });
function* task(id: number) {
yield workers.request();
console.log(`Task ${id} assigned a worker at ${sim.now}`);
yield* timeout(10);
workers.release();
}Shared Resources
Multiple process types sharing a resource:
function* normalJob(id: number) {
yield machine.request();
yield* timeout(10);
machine.release();
}
function* urgentJob(id: number) {
yield machine.request();
yield* timeout(5); // Shorter processing time
machine.release();
}Resource Monitoring
Track resource state over time:
function* monitor(resource: Resource) {
while (true) {
console.log(`Time ${sim.now}: ${resource.inUse}/${resource.capacity} in use, ${resource.queueLength} waiting`);
yield* timeout(10);
}
}
sim.process(() => monitor(server));Best Practices
- Always release resources - Forgetting to release causes deadlocks
- Name your resources - Enables automatic statistics tracking
- Check queue lengths - Monitor
resource.queueLengthto detect bottlenecks - Avoid holding multiple resources - Can cause deadlocks if not careful
- Use time-weighted statistics - Better representation than simple averages
Next Steps
- Learn about Statistics for deeper analysis
- Explore Random Numbers for stochastic behavior
- See Examples for complete resource-based simulations