Passing variables between simpy processes

55 Views Asked by At

I have a basic question that I don’t seem to be able to find the answer to. I just want to pass a variable from a process to another, but I read that I shouldn’t use a return statement to do so, because that can terminate a running process in a while loop. I have the following code:

import simpy as sp
def my_proc(env):
    while True:
        yield env.timeout(2)
        return env.now 

def other_proc(env):
    while True:
        ret_val = yield env.process(my_proc(env))
        print(env.now,ret_val)

env=sp.Environment()

env.process(my_proc(env))
env.process(other_proc(env))
env.run(until=10)

And it seems to run properly printing 2 2, 4 4 , 6 6 … I expected it to not work because the return statement is there, but instead it works properly. Is this the proper way to pass a value from a process to another? Is this the recommended way?

1

There are 1 best solutions below

0
On

Your code has some useless statements. Look:

def my_proc(env):
    # An infinite loop is useless
    # because it has a return statement inside
    # without any condition.
    while True:
        yield env.timeout(2)
        return env.now
        # Here the loop is over


def other_proc(env):
    while True:
        # Here you create a new my_proc process in each iteration.
        # Therefore, the infinite loop in my_proc is useless.
        ret_val = yield env.process(my_proc(env))
        print(env.now,ret_val)


env = sp.Environment()

# You create the my_proc process here and never use it again.
# In other_proc you always create a new instance of my_proc.
# So you should just delete the statement below.
env.process(my_proc(env))

env.process(other_proc(env))
env.run(until=10)

Way 1

The corrected code looks like this

import simpy as sp


def my_proc(env: sp.Environment):
    yield env.timeout(2)
    return env.now


def other_proc(env: sp.Environment):
    while True:
        ret_val = yield env.process(my_proc(env))
        print(env.now, ret_val)


env = sp.Environment()
env.process(other_proc(env))
env.run(until=10)

and still works as you expect.

Way 2

Probably, in some of your real programs the analog of my_proc can contain a lot of heavy logic before the infinite loop, for example. So you do not want to create this process in each iteration in other_proc. You are forced to provide communication between processes. In such case you can use the shared resource (see more in Shared Resources).

In your case the simpy.Store resource is appropriate:

import simpy as sp


def my_proc(env: sp.Environment, resource: sp.Store):
    # Some heavy logic...
    # ...
    while True:
        yield env.timeout(2)
        # Make request for the opportunity to add an item.
        # If the store is full, wait until any item is taken from it.
        yield resource.put(env.now)


def other_proc(env: sp.Environment, resource: sp.Store):
    while True:
        # Wait for the element to appear in the resource.
        ret_val = yield resource.get()
        print(env.now, ret_val)


env = sp.Environment()
# Create shared resource (Store).
# Capacity 1 is enough for your purposes.
shared_resource = sp.Store(env, capacity=1)
# And pass it to the interacting processes.
env.process(my_proc(env, shared_resource))
env.process(other_proc(env, shared_resource))
env.run(until=10)

Way 3

Moreover, there is another way. You can use a shared event but this requires some shared event variable. This is easy to do using a class (or a global variable but this is not recommended):

import simpy as sp


class MyClass:
    def __init__(self, env: sp.Environment):
        self.env = env
        # Create an event
        self.event = env.event()
        # Start processes of the class
        env.process(self.other_proc())
        env.process(self.my_proc())

    def my_proc(self):
        # Again the infinite loop in this method
        while True:
            yield self.env.timeout(2)
            # Succeed the event and passing any value through it
            self.event.succeed(env.now)
            # Recreate the event
            self.event = self.env.event()

    def other_proc(self):
        while True:
            # Wait until the event is triggered
            ret_val = yield self.event
            print(env.now, ret_val)


env = sp.Environment()
class_instance = MyClass(env)
env.run(until=10)