Commit 9251555d authored by Ontje Lünsdorf's avatar Ontje Lünsdorf
Browse files

Merge.

parents f736b226 b499edee
SimPy
=====
**Note:** *Simpy 3 is currently in development. Everything we promise below may
or may not yet exist, may dramatically change or even explode! Nevertheless, we
encourage you to try out the development version and tell us what you think.*
SimPy is a process-based discrete-event simulation framework based on standard
Python. Its event dispatcher is based on Python’s `generators`__ and can also be
used for asynchronous networking or to implement multi-agent systems (with
......
......@@ -22,11 +22,6 @@
</div>
</div>
<p><em><strong>Note:</strong> Simpy 3 is currently in development. Everything
we promise below may or may not yet exist, may dramatically change or even
explode! Nevertheless, we encourage you to try out the development version and
tell us what you think.</em></p>
<p>SimPy is a process-based discrete-event simulation framework based on
standard Python. Its event dispatcher is based on Python’s <a
href="http://docs.python.org/2/glossary.html#term-generator">generators</a> and
......
......@@ -11,10 +11,11 @@ components.
simpy
simpy.core
simpy.monitoring
simpy.resources
simpy.resources.base
simpy.resources.container
simpy.resources.resource
simpy.resources.store
simpy.monitoring
simpy.rt
simpy.util
......@@ -5,15 +5,12 @@
.. automodule:: simpy.core
.. data:: PENDING = object()
Unique object to identify pending values of events.
Performing the simulation of an environment
===========================================
.. autofunction:: peek
.. autofunction:: step
.. autofunction:: simulate
.. autofunction:: all_events
.. autofunction:: any_event
.. autoclass:: Environment
......@@ -42,6 +39,9 @@
Convenience method. Also returns a new instance of :class:`Process`.
Events and helpers
==================
.. autoclass:: Event(env, value=PENDING, name=None)
.. attribute:: callbacks
......@@ -115,6 +115,9 @@
Optional name for this event. Used for :class:`str` / :func:`repr` if
not ``None``.
.. autofunction:: all_events
.. autofunction:: any_event
.. autoclass:: Initialize
......@@ -127,6 +130,9 @@
The :class:`Environment` the event lives in.
Miscellaneous (Scheduling, Interrupt, constants)
================================================
.. autoclass:: Scheduler
:members:
......@@ -146,3 +152,23 @@
.. autoclass:: Interrupt
:members: cause
.. data:: Infinity = inf
Convenience alias for infinity
.. data:: PENDING = object()
Unique object to identify pending values of events
.. data:: HIGH_PRIORITY = 0
Priority of interrupts and Intialize events
.. data:: DEFAULT_PRIORITY = 1
Default priority used by events
.. data:: LOW_PRIORITY = 2
Priority of timeouts
======================================
``simpy.rt`` --- Real-time simulations
======================================
.. automodule:: simpy.rt
.. autoclass:: RealtimeEnvironment
:members:
.. autoclass:: RealtimeScheduler
:members:
===========
Bank Renege
===========
Covers:
- Resources: Resource
- Condition events
A counter with a random service time and customers who renege. Based on the
program bank08.py from TheBank tutorial of SimPy 2. (KGM)
This example models a bank counter and customers arriving t random times. Each
customer has a certain patience. It waits to get to the counter until she’s at
the end of her tether. If she gets to the counter, she uses it for a while
before releasing it.
New customers are created by the ``source`` process every few time steps.
.. literalinclude:: code/bank_renege.py
The simulation's output:
.. literalinclude:: code/bank_renege.out
......@@ -25,6 +25,6 @@ simulation continues.
.. literalinclude:: code/carwash.py
The simulations output:
The simulation's output:
.. literalinclude:: code/carwash.out
Bank renege
0.0000 Customer00: Here I am
0.0000 Customer00: Waited 0.000
3.8595 Customer00: Finished
10.2006 Customer01: Here I am
10.2006 Customer01: Waited 0.000
12.7265 Customer02: Here I am
13.9003 Customer02: RENEGED after 1.174
23.7507 Customer01: Finished
34.9993 Customer03: Here I am
34.9993 Customer03: Waited 0.000
37.9599 Customer03: Finished
40.4798 Customer04: Here I am
40.4798 Customer04: Waited 0.000
43.1401 Customer04: Finished
Bank renege
0.0000 Customer00: Here I am
0.0000 Customer00: Waited 0.000
3.8595 Customer00: Finished
10.2006 Customer01: Here I am
10.2006 Customer01: Waited 0.000
12.7265 Customer02: Here I am
13.9003 Customer02: RENEGED after 1.174
23.7507 Customer01: Finished
34.9993 Customer03: Here I am
34.9993 Customer03: Waited 0.000
37.9599 Customer03: Finished
40.4798 Customer04: Here I am
40.4798 Customer04: Waited 0.000
43.1401 Customer04: Finished
"""
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
RANDOM_SEED = 42
NEW_CUSTOMERS = 5 # Total number of customers
INTERVAL_CUSTOMERS = 10.0 # Generate new customers roughly every x seconds
MIN_PATIENCE = 1 # Min. customer patience
MAX_PATIENCE = 3 # Max. customer patience
def source(env, number, interval, counter):
"""Source generates customers randomly"""
for i in range(number):
c = customer(env, 'Customer%02d' % i, counter, time_in_bank=12.0)
env.start(c)
t = random.expovariate(1.0 / interval)
yield env.timeout(t)
def customer(env, name, counter, time_in_bank):
"""Customer arrives, is served and leaves."""
arrive = env.now
print('%7.4f %s: Here I am' % (arrive, name))
with counter.request() as req:
patience = random.uniform(MIN_PATIENCE, MAX_PATIENCE)
# Wait for the counter or abort at the end of our tether
results = yield req | env.timeout(patience)
wait = env.now - arrive
if req in results:
# We got to the counter
print('%7.4f %s: Waited %6.3f' % (env.now, name, wait))
tib = random.expovariate(1.0 / time_in_bank)
yield env.timeout(tib)
print('%7.4f %s: Finished' % (env.now, name))
else:
# We reneged
print('%7.4f %s: RENEGED after %6.3f' % (env.now, name, wait))
# Setup and start the simulation
print('Bank renege')
random.seed(RANDOM_SEED)
env = simpy.Environment()
# Start processes and simulate
counter = simpy.Resource(env, capacity=1)
env.start(source(env, NEW_CUSTOMERS, INTERVAL_CUSTOMERS, counter))
simpy.simulate(env)
......@@ -28,6 +28,6 @@ refuel the gas station itself.
.. literalinclude:: code/gas_station_refuel.py
The simulations output:
The simulation's output:
.. literalinclude:: code/gas_station_refuel.out
......@@ -2,8 +2,6 @@
Examples
========
All theory is grey. In this section, we present various practical examples that
demonstrate how to uses SimPy's features.
......@@ -12,6 +10,7 @@ Here's a list of examples grouped by features they demonstrate.
Condition events
================
- :doc:`bank_renege`
- :doc:`movie_renege`
......@@ -40,16 +39,17 @@ Resources: Preemptive Resource
Resources: Resource
===================
- :doc:`gas_station_refuel`
- :doc:`bank_renege`
- :doc:`carwash`
- :doc:`gas_station_refuel`
- :doc:`movie_renege`
Resources: Store
================
- :doc:`process_communication`
- :doc:`latency`
- :doc:`process_communication`
Shared events
......@@ -70,6 +70,7 @@ All examples
.. toctree::
bank_renege
carwash
machine_shop
movie_renege
......@@ -77,14 +78,6 @@ All examples
process_communication
latency
.. bank_renege
.. call_center
.. cellphone
.. central-server
.. celluar_automata
.. market
.. mmc
You have ideas for better examples? Please send them to our `mainling list
<https://lists.sourceforge.net/lists/listinfo/simpy-users>`_ or make a pull
request on `bitbucket <https://bitbucket.org/simpy/simpy>`_.
......@@ -22,6 +22,6 @@ Example by:
.. literalinclude:: code/latency.py
The simulations output:
The simulation's output:
.. literalinclude:: code/latency.out
......@@ -27,6 +27,6 @@ priority).
.. literalinclude:: code/machine_shop.py
The simulations output:
The simulation's output:
.. literalinclude:: code/machine_shop.out
......@@ -31,6 +31,6 @@ movie and the number of tickets for the moviegoer.
.. literalinclude:: code/movie_renege.py
The simulations output:
The simulation's output:
.. literalinclude:: code/movie_renege.out
......@@ -27,6 +27,6 @@ Example By:
.. literalinclude:: code/process_communication.py
The simulations output:
The simulation's output:
.. literalinclude:: code/process_communication.out
......@@ -2,33 +2,6 @@
This module contains the implementation of SimPy's core classes. The
most important ones are directly importable via :mod:`simpy`.
- :class:`Environment`: SimPy's central class. It contains the
simulation's state and lets the PEMs interact with it (i.e., schedule
events).
- :class:`~simpy.core.Process`: This class represents a PEM while
it is executed in an environment. An instance of it is returned by
:meth:`Environment.start()`. It inherits :class:`Event`.
- :class:`Interrupt`: This exception is thrown into a process if it gets
interrupted by another one.
- :class:`Event`: A simple event that can be used to implement things
like shared resources.
- :class:`Timeout`: Can be yielded by a PEM to hold its state or wait
for a certain amount of time.
- :class:`Condition`: Groups multiple events and is triggered if a
custom condition on them evaluates to true. There are two default
evaluation functions (:func:`all_events()` and :func:`any_event()`
that are used for :class:`Event`'s implementation of ``__and__`` and
``__or__``.
This module also contains a few functions to simulate an
:class:`Environment`: :func:`peek()`, :func:`step()` and the shortcut
:func:`simulate()`.
"""
import types
from heapq import heappush, heappop
......@@ -41,18 +14,13 @@ if PY2:
import sys
Infinity = float('inf')
"""Convenience alias for infinity."""
Infinity = float('inf') # Convenience alias for infinity
PENDING = object()
"""Unique object to identify pending values of events."""
PENDING = object() # Unique object to identify pending values of events
HIGH_PRIORITY = 0
"""Priority of interrupts and process initialization events."""
DEFAULT_PRIORITY = 1
"""Default priority used by events."""
LOW_PRIORITY = 2
"""Priority of timeouts."""
HIGH_PRIORITY = 0 # Priority of interrupts and Initialize events
DEFAULT_PRIORITY = 1 # Default priority used by events
LOW_PRIORITY = 2 # Priority of timeouts
class Interrupt(Exception):
......@@ -476,8 +444,8 @@ class Process(Event):
if event.ok:
event = self._generator.send(event._value)
else:
# The process has no choice but to handle the failed event (or
# fail itself).
# The process has no choice but to handle the failed event
# (or fail itself).
event.defused = True
event = self._generator.throw(event._value)
except StopIteration as e:
......
"""
SimPy's monitoring capabilities will be added in version 3.1.
"""
......@@ -16,7 +16,23 @@ Infinity = float('inf')
class RealtimeScheduler(Scheduler):
def __init__(self, env, initial_time, factor, strict):
"""This :class:`~simpy.core.Scheduler` delays the :meth:`pop()` operation
to adjust to the wallclock time.
The arguments *env* and an *initial_time* are passed to
:class:`~simpy.core.Scheduler`.
A simulation time step will take *factor* seconds of real time (one second
by default), e.g. if you simulate from ``0`` until ``3`` with
``factor=0.5``, the :func:`~simpy.core.simulate()` call will take at least
1.5 seconds.
If the processing of the events for a time step takes too long,
a :exc:`RuntimeError` is raised by :meth:`pop()`. You can disable this
behavior by setting *strict* to ``False``.
"""
def __init__(self, env, initial_time, factor=1.0, strict=True):
Scheduler.__init__(self, env, initial_time)
self.sim_start = initial_time
self.real_start = time()
......@@ -24,6 +40,15 @@ class RealtimeScheduler(Scheduler):
self.strict = strict
def pop(self):
"""Return the next event from the schedule.
The call is delayed corresponding to the real-time *factor* of the
scheduler.
If the events of a simulation time step are processed to slowly for the
given *factor* and if *strict* is enabled, raise a :exc:`RuntimeError`.
"""
event = super(RealtimeScheduler, self).pop()
sim_delta = self.now - self.sim_start
......@@ -41,15 +66,11 @@ class RealtimeScheduler(Scheduler):
class RealtimeEnvironment(Environment):
"""
A simulation time step in this environment will take *factor* seconds of
real time (one second by default), e.g. if you simulate from ``0`` until
``3`` with ``factor=0.5``, the call will take at least 1.5 seconds. If the
processing of the events for a time step takes too long, a
:exc:`RuntimeError` is raised. You can disable this behavior by setting
*strict* to ``False``.
"""
"""This :class:`~simpy.core.Environment` uses a :class:`RealtimeScheduler`
by default, so a simulation time step will take *factor* seconds of real
time (see :class:`RealtimeScheduler` for more information).
"""
def __init__(self, initial_time=0, factor=1.0, strict=True):
Environment.__init__(self, initial_time, RealtimeScheduler(
self, initial_time, factor, strict))
......@@ -20,13 +20,14 @@ def start_delayed(env, peg, delay):
Just pass it as a first parameter to ``start()``::
>>> from simpy import Environment, simulate
>>> from simpy.util import start_delayed
>>> def pem(env, x):
... print('%s, %s' % (env.now, x))
... yield env.timeout(1)
...
>>> env = Environment()
>>> start_delayed(env, pem(env, 3), 5)
Process(starter)
>>> proc = start_delayed(env, pem(env, 3), 5)
>>> simulate(env)
5, 3
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment