Process Interaction¶
The Process
instance that is returned by
Environment.process()
can be utilized for process interactions. The two
most common examples for this are to wait for another process to finish and to
interrupt another process while it is waiting for an event.
Waiting for a Process¶
As it happens, a SimPy Process
can be used like an event
(technically, a process actually is an event). If you yield it, you are
resumed once the process has finished. Imagine a car-wash simulation where cars
enter the car-wash and wait for the washing process to finish. Or an airport
simulation where passengers have to wait until a security check finishes.
Lets assume that the car from our last example magically became an electric vehicle. Electric vehicles usually take a lot of time charging their batteries after a trip. They have to wait until their battery is charged before they can start driving again.
We can model this with an additional charge()
process for our car.
Therefore, we refactor our car to be a class with two process methods:
run()
(which is the original car()
process function) and charge()
.
The run
process is automatically started when Car
is instantiated.
A new charge
process is started every time the vehicle starts parking. By
yielding the Process
instance that
Environment.process()
returns, the run
process starts waiting for
it to finish:
>>> class Car(object):
... def __init__(self, env):
... self.env = env
... # Start the run process everytime an instance is created.
... self.action = env.process(self.run())
...
... def run(self):
... while True:
... print('Start parking and charging at %d' % self.env.now)
... charge_duration = 5
... # We yield the process that process() returns
... # to wait for it to finish
... yield self.env.process(self.charge(charge_duration))
...
... # The charge process has finished and
... # we can start driving again.
... print('Start driving at %d' % self.env.now)
... trip_duration = 2
... yield self.env.timeout(trip_duration)
...
... def charge(self, duration):
... yield self.env.timeout(duration)
Starting the simulation is straight forward again: We create an environment, one (or more) cars and finally call meth:~Environment.simulate().
>>> import simpy
>>> env = simpy.Environment()
>>> car = Car(env)
>>> env.run(until=15)
Start parking and charging at 0
Start driving at 5
Start parking and charging at 7
Start driving at 12
Start parking and charging at 14
Interrupting Another Process¶
Imagine, you don’t want to wait until your electric vehicle is fully charged but want to interrupt the charging process and just start driving instead.
SimPy allows you to interrupt a running process by calling its
interrupt()
method:
>>> def driver(env, car):
... yield env.timeout(3)
... car.action.interrupt()
The driver
process has a reference to the car’s action
process. After
waiting for 3 time steps, it interrupts that process.
Interrupts are thrown into process functions as Interrupt
exceptions that can (should) be handled by the interrupted process. The process
can then decide what to do next (e.g., continuing to wait for the original
event or yielding a new event):
>>> class Car(object):
... def __init__(self, env):
... self.env = env
... self.action = env.process(self.run())
...
... def run(self):
... while True:
... print('Start parking and charging at %d' % self.env.now)
... charge_duration = 5
... # We may get interrupted while charging the battery
... try:
... yield self.env.process(self.charge(charge_duration))
... except simpy.Interrupt:
... # When we received an interrupt, we stop charging and
... # switch to the "driving" state
... print('Was interrupted. Hope, the battery is full enough ...')
...
... print('Start driving at %d' % self.env.now)
... trip_duration = 2
... yield self.env.timeout(trip_duration)
...
... def charge(self, duration):
... yield self.env.timeout(duration)
When you compare the output of this simulation with the previous example,
you’ll notice that the car now starts driving at time 3
instead of 5
:
>>> env = simpy.Environment()
>>> car = Car(env)
>>> env.process(driver(env, car))
<Process(driver) object at 0x...>
>>> env.run(until=15)
Start parking and charging at 0
Was interrupted. Hope, the battery is full enough ...
Start driving at 3
Start parking and charging at 5
Start driving at 10
Start parking and charging at 12
What’s Next¶
We just demonstrated two basic methods for process interactions—waiting for
a process and interrupting a process. Take a look at the
Topical Guides or the Process
API
reference for more details.
In the next section we will cover the basic usage of shared resources.