Background
SimPy process is said to be a generator in the document, which I expected to have the send method as in PEP 342.
Processes are described by simple Python generators. You can call them process function or process method, depending on whether it is a normal function or method of a class. During their lifetime, they create events and yield them in order to wait for them to be triggered.
I can use send to send a message to a generator from another, for instance to inject a charging station generator into the ev generator.
from typing import Dict, Optional, Generator
import time
def ev(env) -> Generator:
while True:
next_charging_station = yield
print("next_charging_station[{}]".format(next_charging_station))
def dispathcer(env, ev) -> Generator:
while True:
time.sleep(3)
print('Dispatching the next charging station')
ev.send("new station")
process_ev = ev(env)
next(process_ev)
process_dispatcher = dispathcer(env, process_ev)
Dispatching the next charging station
next_charging_station[new station]
Dispatching the next charging station
next_charging_station[new station]
However, the SymPy process does not have the send method.
import simpy
env = simpy.Environment()
def ev(env):
while True:
next_charging_station = yield
print("next_charging_station[{}]".format(next_charging_station))
def dispathcer(env, ev):
while True:
print('Dispatching the next charging station at %d' % (env.now))
ev.send("new station")
rocess_ev = env.process(ev(env))
process_dispatcher = env.process(dispathcer(env, process_ev))
-----
Dispatching the next charging station at 0
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-12-ece25f162510> in <module>
1 process_ev = env.process(ev(env))
----> 2 process_dispatcher = env.process(dispathcer(env, process_ev))
<ipython-input-11-b89aeb1a9073> in dispathcer(env, ev)
11 while True:
12 print('Dispatching the next charging station at %d' % (env.now))
---> 13 ev.send("hoge")
AttributeError: 'Process' object has no attribute 'send'
Question
Please help understand the reason for this error if this is as designed (send and possibly close/throw are not available) or if I misunderstood something. I suppose all the synchronizations need to be done by the SimPy environment via its events, otherwise the environment may lose track of the states of processes, but not sure.
Please advise if there is a way to update the memory in a process from another. For instance, how can I change the code to dynamically inject a charging station process into the ev process.
import simpy
env = simpy.Environment()
def charging_station(env):
print('Start charging at %d' % (env.now))
charge_duration = 3
yield env.timeout(charge_duration)
return
def ev(env):
while True:
print('Start driving at %d' % (env.now))
driving_duration = 5
yield env.timeout(driving_duration)
print('Stop at a charging station at %d' % (env.now))
# [Q] Instead of creating a charging process inside the ev process,
# how to get it injected?
yield env.process(charging_station(env)) # <-----
env.process(ev(env))
env.run(until=20)
-----
Start driving at 0
Stop at a charging station at 5
Start charging at 5
Start driving at 8
Stop at a charging station at 13
Start charging at 13
Start driving at 16
e.g. something like this if possible.
def new_ev(env): # <---- how to implement?
while True:
next_charging_station = yield # Get the next station process
print('Start charging at %d' % (env.now))
yield next_charging_station
print('Start driving at %d' % (env.now))
driving_duration = 5
yield env.timeout(driving_duration)
It looks the injection into a process can be possible only at its creation. Hence one way can be inject the dispatcher into the ev process, then get a charging station from inside the ev process. However, would like to explicitly inject any instances into it instead of pulling from inside it.
import random
import simpy
env = simpy.Environment()
class Dispatcher(object):
env = None
def __init__(self, env):
self.env = env
print('Start dispatcher at time %d' % self.env.now)
# Start the run process everytime an instance is created.
#self.process = env.process(self.run())
def run(self):
while True:
print('Start dispatcher at time %d' % self.env.now)
yield self.env.timeout(1)
def next_charger_station(self):
return self._charge(random.randint(1, 1000), self.env)
def _charge(self, id, env):
print('station %s start charging at time %d' % (id, env.now))
yield env.timeout(5)
return
def ev(env, dispatcher):
while True:
print('EV stops at the new charging station at time %d' % (env.now))
yield env.process(dispatcher.next_charger_station())
print('EV start driving from the charging station at time %d' % (env.now))
yield env.timeout(5)
dispatcher = Dispatcher(env)
process_ev = env.process(ev(env, dispatcher))
env.run(until=30)