diff --git a/simulation/app.py b/simulation/app.py index 0bca4c8..71eddd9 100644 --- a/simulation/app.py +++ b/simulation/app.py @@ -1,4 +1,4 @@ -from dataclasses import asdict, dataclass +from dataclasses import dataclass import numpy as np import pandas as pd @@ -39,22 +39,36 @@ class Server(Process): class CustomerGenerator(Process): + def __init__(self, lam=40, servers=[]): + self.lam = lam + self.servers = servers + super().__init__() + def run(self): while True: - wait_for = float(max(0, (np.random.poisson(lam=40, size=1) / 10)[0])) + wait_for = float(max(0, (np.random.poisson(lam=self.lam, size=1) / 10)[0])) customer = Customer(arrived_at=self.simulation.clock) customers_unhandled.append(customer) - for server in servers: + for server in self.servers: server.resume() yield from self.hold(wait_for) -servers = [Server() for _ in range(2)] -simulation = Simulation(processes=[CustomerGenerator(), *servers]) -simulation.start() +def run_simulation(n_servers=2, lam=40): + servers = [Server() for _ in range(n_servers)] + simulation = Simulation( + processes=[CustomerGenerator(servers=servers, lam=lam), *servers] + ) + simulation.start() -df = pd.DataFrame([asdict(customer) for customer in customers_handled]).assign( - queue_time=lambda row: row["started_at"] - row["arrived_at"] -) -print(f"\nservers: {len(servers)}") -print(df[["queue_time", "handling_time"]].mean()) + df_customers = pd.DataFrame( + [customer.__dict__ for customer in customers_handled] + ).assign(queue_time=lambda row: row["started_at"] - row["arrived_at"]) + df_servers = pd.DataFrame([server.__dict__ for server in servers]).set_index("id") + print("\n") + print(df_customers[["queue_time", "handling_time"]].mean()) + print(f"\nservers: {len(servers)}") + print(df_servers[["utilization"]]) + + +run_simulation(n_servers=2, lam=30) diff --git a/simulation/lib.py b/simulation/lib.py index 9c92f35..2d7b626 100644 --- a/simulation/lib.py +++ b/simulation/lib.py @@ -17,19 +17,32 @@ class Process(BaseProcess): def __init__(self): self.id: int = 1 self.simulation = BaseSimulation() + self.started_at: float = 0 self.resume_at: float = 0 + self.time_active: float = 0 + self.utilization: float = 0 self.suspended = False self._gen = self.run() - @property - def name(self): - return f"{self.__class__.__name__} {self.id}" + def start(self, simulation, id): + self.id = id + self.started_at = simulation.clock + self.simulation = simulation def hold(self, hold_for: float): hold_for_formatted = "{:.2f}".format(hold_for) self.simulation.log(f"holding {self.name} for {hold_for_formatted} seconds") self.resume_at = self.simulation.clock + hold_for + t_start = self.simulation.clock yield + t_end = self.simulation.clock + self.time_active += t_end - t_start + try: + self.utilization = self.time_active / ( + self.simulation.clock - self.started_at + ) + except Exception as e: + print(e) def suspend(self): self.suspended = True @@ -42,6 +55,10 @@ class Process(BaseProcess): self.suspended = False next(self._gen) + @property + def name(self): + return f"{self.__class__.__name__} {self.id}" + class Simulation(BaseSimulation): def __init__(self, processes: list[Process]): @@ -56,8 +73,7 @@ class Simulation(BaseSimulation): for p in self.processes if p.__class__.__name__ == process.__class__.__name__ ] - process.id = 1 + len(processes_with_same_class) - process.simulation = self + process.start(simulation=self, id=1 + len(processes_with_same_class)) self.processes.append(process) @property