1

output printing the len of arrival and service timesI am trying to implement an M/M/1 markovian process with exponential inter arrival and exponential service times using simpy. The code runs fine but I dont quite get the expected results. Also the number of list items in arrival times is lesser than the number of list items in service time after the code is run.

# make a markovian queue
# make a server as a resource
# make customers at random times
# record the customer arrival time
# customer gets the resource
# record when the customer got the resource
# serve the customers for a random time using resource
# save this random time as service time
# customer yields the resource and next is served

import statistics
import simpy
import random


arrival_time = []
service_time = []
mean_service = 2.0
mean_arrival = 1.0
num_servers = 1

class Markovian(object):
    def __init__(self, env, num_servers):
        self.env = env
        self.servers  = simpy.Resource(env, num_servers)
        #self.action = env.process(self.run())
    def server(self,packet ):
        #timeout after random service time
        t = random.expovariate(1.0/mean_service)
        #service_time.append(t)
        yield self.env.timeout(t)
    
    def getting_service(env, packet, markovian):
        # new packet arrives in the system
        arrival_time = env.now
        with markovian.servers.request() as req:
            yield req
            yield env.process(markovian.server(packet))
        service_time.append(env.now - arrival_time)
    
    def run_markovian(env,num_servers):
        markovian = Markovian(env,num_servers)
        packet = 0
        #generate new packets
        while True:
            t = random.expovariate(1.0/mean_arrival)
            arrival_time.append(t)
            yield env.timeout(t)
            packet +=1
            env.process(Markovian.getting_service(env,packet,markovian))

    def get_average_service_time(service_time):
        average_service_time = statistics.mean(service_time)
        return average_service_time
    
def main():
    random.seed(42)

    env= simpy.Environment()
    env.process(Markovian.run_markovian(env,num_servers))
    env.run(until = 50)
    print(Markovian.get_average_service_time(service_time))
    print (arrival_time)
    print (service_time)
    

    
if __name__ == "__main__":
    main()

  • 1
    "I dont quite get the expected results." In what way? It may very well be that your expectations are off if, for instance, you expect to get the theoretical steady-state mean (see http://homepages.cae.wisc.edu/~ie642/content/Techniques/Warmup/warmup.htm for an explanation). – pjs Dec 07 '20 at 19:54
  • Is Simpy a requirement for you? I'm asking becasue a [single server queue can be simulated very easily with just a loop](https://stackoverflow.com/a/65066699/2166798). – pjs Dec 07 '20 at 20:13
  • No Simpy is not a requirement. But I wanted to learn using it well since I can then use it for an M/M/K server as well in which customers can be switched on and off. Further, I dont get the expected results as you can see from this screenshot that len of arrival times is more than len of service times. – Kilam_Ruhdam Dec 08 '20 at 14:50
  • Have you tried comparing your implementation to one of the many available online by doing a search on "simpy m/m/1 example"? – pjs Dec 08 '20 at 21:45

1 Answers1

1

Hello there were basically one bug in your code and two queuing theory misconceptions:

Bug 1) the definition of the servers were inside the class, this makes the model behaves as a M/M/inf not M/M/1

Answer: I put the definition of your resources out the the class, and pass the servers not the num_servers from now on.

Misconception 1: with the times as you defined:

mean_service = 2.0 mean_arrival = 1.0

The system will generate much more packets and it is able to serve. That's why the size of the lists were so different.

Answer: mean_service = 1.0 mean_arrival = 2.0

Misconception 2:

What you call service time in your code is actually system time.

I also put some prints in your code so we could see that is doing. Fell free to comment them. And there is no need for the library Statistics, so I commented it too.

I hope this answer is useful to you.

# make a markovian queue
# make a server as a resource
# make customers at random times
# record the customer arrival time
# customer gets the resource
# record when the customer got the resource
# serve the customers for a random time using resource
# save this random time as service time
# customer yields the resource and next is served

#import statistics
import simpy
import random


arrivals_time = []
service_time = []
waiting_time = []

mean_service = 1.0
mean_arrival = 2.0
num_servers = 1

class Markovian(object):
    def __init__(self, env, servers):
        self.env = env
        #self.action = env.process(self.run())

    #def server(self,packet ):
        #timeout after random service time
     #   t = random.expovariate(1.0/mean_service)
        #service_time.append(t)
      #  yield self.env.timeout(t)
    
    def getting_service(env, packet, servers):
        # new packet arrives in the system

        begin_wait = env.now
        req = servers.request()
        yield req
        
        begin_service = env.now
        waiting_time.append(begin_service - begin_wait)

        print('%.1f Begin Service of packet %d' % (begin_service, packet))
        
        yield env.timeout(random.expovariate(1.0/mean_service))
        
        service_time.append(env.now - begin_service)

        yield servers.release(req)
        print('%.1f End Service of packet %d' % (env.now, packet))

    
    def run_markovian(env,servers):
        markovian = Markovian(env,servers)
        packet = 0
        #generate new packets
        while True:
            t = random.expovariate(1.0/mean_arrival)
            yield env.timeout(t)
            arrivals_time.append(t)
            packet +=1
            print('%.1f Arrival of packet %d' % (env.now, packet))

            env.process(Markovian.getting_service(env,packet,servers))


    def get_average_service_time(service_time):
        average_service_time = statistics.mean(service_time)
        return average_service_time
    
def main():
    random.seed(42)

    env= simpy.Environment()
    servers  = simpy.Resource(env, num_servers)

    env.process(Markovian.run_markovian(env,servers))
    env.run(until = 50)
    
    print(Markovian.get_average_service_time(service_time))
    print ("Time between consecutive arrivals \n", arrivals_time)
    print("Size: ", len(arrivals_time))
    print ("Service Times \n", service_time)
    print("Size: ", len(service_time))
    print ("Waiting Times \n", service_time)
    print (waiting_time)
    print("Size: ",len(waiting_time))


    
if __name__ == "__main__":
    main()