Skip to content

Instantly share code, notes, and snippets.

@christlc
Created November 1, 2017 00:13
Show Gist options
  • Save christlc/02a1878b8350c3785071058f7bd4b20f to your computer and use it in GitHub Desktop.
Save christlc/02a1878b8350c3785071058f7bd4b20f to your computer and use it in GitHub Desktop.
A task simulation tool to illustrate load factor vs wait time in Simpy
"""
Adapted from https://simpy.readthedocs.io/en/latest/examples/bank_renege.html
Bank renege example
Covers:
- Resources: Resource
- Condition events
Scenario:
A counter with a random service time and customers who renege. Based on the
program bank08.py from TheBank tutorial of SimPy 2. (KGM)
"""
import random
import simpy
import simpy.rt
def start_simulation(RANDOM_SEED = 1098,
NEW_CUSTOMERS = 250, # Total number of customers
INTERVAL_CUSTOMERS = 1.0, # Generate new customers roughly every x seconds
PATIENCE = 100000000, # customer patience
TIME_IN_JOB = 1.0,
RANDOM_TYPE = True,
REALTIME = 0.5,
VERBOSE = True):
# Setup and start the simulation
def source(env, number, interval, counter, verbose):
"""Source generates customers randomly"""
env.work_time = []
env.wait_time = []
for i in range(number):
c = customer(env, 'Task%02d' % i, counter, time_in_bank=TIME_IN_JOB, verbose=verbose)
env.process(c)
if(RANDOM_TYPE):
t = random.expovariate(1.0 / interval)
else:
t = interval
yield env.timeout(t)
def customer(env, name, counter, time_in_bank, verbose=True):
"""Customer arrives, is served and leaves."""
arrive = env.now
if(verbose):
print('%7.4f %s: Here I am' % (arrive, name))
with counter.request() as req:
patience = PATIENCE
# Wait for the counter or abort at the end of our tether
results = yield req | env.timeout(patience)
wait = env.now - arrive
env.wait_time.append(wait)
if req in results:
# We got to the counter
if(verbose):
print('%7.4f %s: Waited %6.3f' % (env.now, name, wait))
if(RANDOM_TYPE):
tib = random.expovariate(1.0 / time_in_bank)
else:
tib = time_in_bank
env.work_time.append(tib)
yield env.timeout(tib)
if(verbose):
print('%7.4f %s: Finished' % (env.now, name))
else:
# We reneged
if(verbose):
print('%7.4f %s: RENEGED after %6.3f' % (env.now, name, wait))
print('Task Simulation')
random.seed(RANDOM_SEED)
if(REALTIME is not None):
env = simpy.rt.RealtimeEnvironment(factor=REALTIME)
else:
env = simpy.Environment()
# Start processes and run
counter = simpy.Resource(env, capacity=1)
proc = env.process(source(env, NEW_CUSTOMERS, INTERVAL_CUSTOMERS, counter, VERBOSE))
env.run(until=proc)
print("Simulated number of tasks: %d" %NEW_CUSTOMERS)
print("Average task length: %7.2f" % (sum(env.work_time)/NEW_CUSTOMERS))
print("Average wait time: %7.2f" % (sum(env.wait_time)/NEW_CUSTOMERS))
print("Total time taken %7.2f" % float(env.now))
print("Period Busy %2.2f %%" % (float(sum(env.work_time))/float(env.now)*100))
##
# CASE 1
start_simulation(NEW_CUSTOMERS = 100, # Total number of customers
INTERVAL_CUSTOMERS = 1.0, # Generate new customers roughly every x seconds
TIME_IN_JOB = 1.0,
RANDOM_TYPE = False,
VERBOSE = True
)
# CASE 2
start_simulation(NEW_CUSTOMERS = 100,
RANDOM_TYPE=True)
# CASE 2b
# Wait time actually grows over time
start_simulation(NEW_CUSTOMERS = 250, RANDOM_TYPE=True, REALTIME=None)
start_simulation(NEW_CUSTOMERS=750, RANDOM_TYPE=True, VERBOSE=False, REALTIME=None)
start_simulation(NEW_CUSTOMERS=5000, RANDOM_TYPE=True, VERBOSE=False, REALTIME=None)
# Solution
# Tasks coming in slightly faster
start_simulation(RANDOM_TYPE=True, INTERVAL_CUSTOMERS=1.0, TIME_IN_JOB=0.8)
start_simulation(NEW_CUSTOMERS=100000, RANDOM_TYPE=True, INTERVAL_CUSTOMERS=1.0, TIME_IN_JOB=0.8, VERBOSE=False, REALTIME=None)
start_simulation(NEW_CUSTOMERS=100000, RANDOM_TYPE=True, INTERVAL_CUSTOMERS=1.0, TIME_IN_JOB=0.9, VERBOSE=False, REALTIME=None)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment