increase execution speed and add process names

This commit is contained in:
2024-08-12 08:49:47 +02:00
parent c5cdca829d
commit 16a236cba7
2 changed files with 38 additions and 20 deletions

View File

@@ -12,25 +12,28 @@ class Customer:
started_at: float | None = None
handling_time: float | None = None
finished_at: float | None = None
being_handled: bool = False
customers: list[Customer] = []
customers_unhandled: list[Customer] = []
customers_in_progress: list[Customer] = []
customers_handled: list[Customer] = []
class Server(Process):
def run(self):
while True:
unhandled_customers = [c for c in customers if c.being_handled is False]
if len(unhandled_customers) > 0:
customer = unhandled_customers[0]
customer.being_handled = True
if len(customers_unhandled) > 0:
customer = customers_unhandled[0]
customers_unhandled.remove(customer)
customers_in_progress.append(customer)
customer.started_at = self.simulation.clock
handling_time = abs(float(np.random.normal(5, 2.5, size=1)[0]))
handling_time = float(max(0, np.random.normal(5, 2.5, size=1)[0]))
yield from self.hold(handling_time)
customer.handling_time = handling_time
customer.finished_at = self.simulation.clock
self.simulation.log(f"unhandled customers: {len(unhandled_customers)}")
customers_in_progress.remove(customer)
customers_handled.append(customer)
self.simulation.log(f"unhandled customers: {len(customers_unhandled)}")
else:
yield from self.suspend()
@@ -38,19 +41,19 @@ class Server(Process):
class CustomerGenerator(Process):
def run(self):
while True:
wait_for = float(abs(np.random.poisson(lam=4, size=1)[0]))
wait_for = float(max(0, (np.random.poisson(lam=40, size=1) / 10)[0]))
customer = Customer(arrived_at=self.simulation.clock)
customers.append(customer)
customers_unhandled.append(customer)
for server in servers:
server.resume()
yield from self.hold(wait_for)
servers = [Server() for _ in range(1)]
servers = [Server() for _ in range(2)]
simulation = Simulation(processes=[CustomerGenerator(), *servers])
simulation.start()
df = pd.DataFrame([asdict(customer) for customer in customers]).assign(
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)}")

View File

@@ -6,6 +6,7 @@ class BaseSimulation:
def log(self, msg):
print(f"{'{:.2f}'.format(self.clock)}: {msg}")
pass
class BaseProcess(Protocol):
@@ -14,26 +15,30 @@ class BaseProcess(Protocol):
class Process(BaseProcess):
def __init__(self):
self.id: int = 1
self.simulation = BaseSimulation()
self.resume_at: float = 0
self.suspended = False
self._gen = self.run()
@property
def name(self):
return f"{self.__class__.__name__} {self.id}"
def hold(self, hold_for: float):
self.simulation.log(
f"holding {self.__class__.__name__} for {'{:.2f}'.format(hold_for)} seconds"
)
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
yield
def suspend(self):
self.suspended = True
self.simulation.log(f"{self.__class__.__name__} suspended")
self.simulation.log(f"{self.name} suspended")
yield
def resume(self):
if self.suspended is True:
self.simulation.log(f"{self.__class__.__name__} resumed")
self.simulation.log(f"{self.name} resumed")
self.suspended = False
next(self._gen)
@@ -41,9 +46,19 @@ class Process(BaseProcess):
class Simulation(BaseSimulation):
def __init__(self, processes: list[Process]):
self.clock = 0
self.processes = processes
self.processes = []
for process in processes:
process.simulation = self
self.register_process(process)
def register_process(self, process):
processes_with_same_class = [
p
for p in self.processes
if p.__class__.__name__ == process.__class__.__name__
]
process.id = 1 + len(processes_with_same_class)
process.simulation = self
self.processes.append(process)
@property
def processes_sorted(self):
@@ -54,7 +69,7 @@ class Simulation(BaseSimulation):
def start(self):
self.log("simulation started")
while self.clock < 100:
while self.clock < 1000:
current_process = self.processes_sorted[0]
self.clock = current_process.resume_at
next(current_process._gen)