Search code examples
pythonpython-2.7python-3.xsimpy

Converting from SimPy2 to SimPy3


I am trying to simulate customers going to a bank. And I want to print the average length of the queue, and each value pair of time a request begins and the pairs [time of request or release, length of queue]

I am aware that there is no monitor class in simpy3, so I tried using the example here Below I have left the relevant code from the file I'm converting from and my attempt to convert it. simpy2 and python2

from SimPy.Simulation import *
import random as rnd

interarrival_time = 10.0
service_time = 8.0


class CustomerGenerator( Process ):
    def produce( self, b ):
        while True:
            c = Customer( b )
            c.start( c.doit() )
            yield hold, self, rnd.expovariate(1.0/interarrival_time)


class Customer( Process ):
    def __init__( self, resource ):
        Process.__init__( self )
        self.bank = resource

    def doit( self ):
        yield request, self, self.bank
        yield hold, self, self.bank.servicetime()
        yield release, self, self.bank

class Bank( Resource ):
    def servicetime( self ):
        return rnd.expovariate(1.0/service_time)


initialize()

bank = Bank( capacity=1, monitored=True, monitorType=Monitor )

src = CustomerGenerator()
activate( src, src.produce( bank ) )

simulate( until=100)


print bank.waitMon.mean()
print

for evt in bank.waitMon:
    print evt[0], evt[1]

simpy3 and python3

from simpy import *
import random as rnd

interarrival_time = 10.0
service_time = 8.0


def produce( env, b ):
    while True:
        customer(env,b)
        yield env.timeout(rnd.expovariate(1.0/interarrival_time))

def customer(env,bank):
    yield bank.request()
    yield env.timeout(bank.servicetime())
    bank.release()

class MonitoredResource(Resource):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.data = []
        self.num_requests = 0
    def mean(self):
        try:
            mean = 0
            for el in self.data:
                mean += el[1]
            mean /= self.num_requests
            return mean
        except ZeroDivisionError:
            pass
    def request(self, *args, **kwargs):
        self.data.append((self._env.now, len(self.queue)))
        self.num_requests += 1 
        return super().request(*args, **kwargs)

    def release(self, *args, **kwargs):
        self.data.append((self._env.now, len(self.queue)))
        return super().release(*args, **kwargs)

class Bank(MonitoredResource):
    def servicetime( self ):
        return rnd.expovariate(1.0/service_time)


env = Environment()
bank = Bank(env,capacity=1)

src = env.process(produce(env,bank))

env.run( until=100)


print(bank.mean())
print()

for evt in bank.data:
    print(evt[0], evt[1])

How can I get the output of my SimPy3 simulator to resemble the SimPy2 simulator instead of just printing None?


Solution

  • It seems I just needed to tell release() which request() was being released to get the desired output. And to run Customer as a process.

    from simpy import *
    import random as rnd
    
    interarrival_time = 10.0
    service_time = 8.0
    
    
    def produce( env, bank ):
        print("generating")
        while True:
            env.process(customer(env,bank))
            t = rnd.expovariate(1.0/interarrival_time)
            yield env.timeout(t)
    
    def customer(env,bank):
        req = bank.request()
        yield req
        yield env.timeout(bank.servicetime())
        bank.release(req)
    
    class MonitoredResource(Resource):
        def __init__(self, *args, **kwargs):
            super().__init__(*args, **kwargs)
            self.data = []
            self.num_requests = 0
    
        def mean(self):
            if(self.num_requests > 0):
                mean = 0
                for el in self.data:
                    mean += el[1]
                mean /= self.num_requests
                return mean
    
        def request(self, *args, **kwargs):
            self.data.append((self._env.now, len(self.queue)))
            self.num_requests += 1 
            return super().request(*args, **kwargs)
    
        def release(self, *args, **kwargs):
            self.data.append((self._env.now, len(self.queue)))
            return super().release(*args, **kwargs)
    
    class Bank(MonitoredResource):
        def __init__(self, *args, **kwargs):
            super().__init__(*args, **kwargs)
        def servicetime( self ):
            return rnd.expovariate(1.0/service_time)
    
    
    env = Environment()
    bank = Bank(env,capacity=1)
    #bank = Bank( capacity=1, monitored=True, monitorType=Monitor )
    
    src = env.process(produce(env,bank))
    
    env.run(until=100)
    
    
    print(bank.mean())
    print()
    
    for evt in bank.data:
        print(evt[0], evt[1])