How do I make Simpy simulation to depict a markovian M/M/1 process?

544 views Asked by At

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

There are 1 answers

0
Eduardo Pécora On

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()