def _agent_accepting_travelers(self, name) -> None: agent = Resource(1) # Models how the agent is busy processing a traveler. while True: # Are we on break yet? That coffee won't drink itself. self._agents_working.wait() info(f"Agent {name}/{self.num} ready") # Is anybody in there? if self._travelers_waiting.is_empty(): debug(f"Agent {name}/{self.num} waiting for travelers") self._traveler_ready.turn_off().wait() continue # Check back if we've gone on break while waiting for somebody. # Accept the next traveler traversing the checkpoint. traveler_next = self._travelers_waiting.peek() debug(f"Agent {name}/{self.num} about to process traveler {traveler_next.local.name}") traveler_next.local.agent = agent traveler_next.local.agent_name = f"{name}/{self.num}" self._travelers_waiting.pop() # Allow the next traveler to "use" this agent, so we may then wait until it's done traversing. advance(0.0) debug(f"Agent {name}/{self.num} doing the processing.") with agent.using(): debug(f"Agent {name}/{self.num} done with the processing.")
def test_auto_log_resource_take_again(auto_logger): def process(res): local.name = "proc" res.take(2) advance(10) res.take(3) advance(10) res.release(5) sim = Simulator(name="sim") resource = Resource(5, name="res") sim.add(process, resource) sim.run() check_log( auto_logger, (logging.INFO, 0.0, "", "Simulator", "sim", "add", dict(fn=process, args=(resource, ), kwargs={})), (logging.INFO, 0.0, "", "Simulator", "sim", "run", dict(duration=inf)), (logging.INFO, 0.0, "proc", "Resource", "res", "take", dict(num_instances=2, free=5)), (logging.INFO, 0.0, "proc", "Process", "proc", "advance", dict(delay=10.0)), (logging.INFO, 10.0, "proc", "Resource", "res", "take", dict(num_instances=3, free=3)), (logging.WARNING, 10.0, "proc", "Resource", "res", "take-again", dict(already=2, more=3)), (logging.INFO, 10.0, "proc", "Process", "proc", "advance", dict(delay=10.0)), (logging.INFO, 20.0, "proc", "Resource", "res", "release", dict(num_instances=5, keeping=0, free=5)), (logging.INFO, 20.0, "proc", "Process", "proc", "die-finish", {}), (logging.INFO, 20.0, "", "Simulator", "sim", "stop", {}))
def run_resource_test_incoherent(num_take: int, num_release: int): sim = Simulator() resource = Resource(5) sim.add(take_M_release_N, resource, num_take, num_release) with pytest.raises(ValueError): sim.run() assert resource.num_instances_free >= 0 assert resource.num_instances_total == 5
def run_test_resource(resource_taker: ResourceTaker, num_instances: int, expected: List[float]) -> None: sim = Simulator() resource = Resource(num_instances) log: List[float] = [] for n in range(8): sim.add(resource_taker, resource, float(n + 1), log) sim.run() assert expected == pytest.approx(log)
def test_resource_release_while_holding_none(): def proc(resource: Resource) -> None: resource.release() pytest.fail() sim = Simulator() resource = Resource(1) sim.add(proc, resource) with pytest.raises(RuntimeError): sim.run()
def test_resource_timeout(): resource = Resource(1) log = [] def take_but_balk(name, delay_balk): try: with resource.using(timeout=delay_balk): advance(20.0) log.append((name, "finish")) except Timeout: log.append((name, "balk")) sim = Simulator() sim.add(take_but_balk, "a", 10.0) sim.add_in(5.0, take_but_balk, "b", 10.0) sim.run() assert log == [("b", "balk"), ("a", "finish")]
def test_log_additional_fields(logger): def ordeal(queue, signal, resource): logger.debug("debug") advance(10) logger.info("info") pause() logger.warning("warning") queue.join() logger.error("error", extra=dict(sim_process="the-process")) signal.wait() logger.critical("critical") resource.take() advance(10) logger.critical("finish", extra=dict(sim_time=1000.0)) resource.release() def do_resume(proc_ordeal): advance(15) proc_ordeal.resume() def do_pop(queue): advance(30) queue.pop() def do_open(signal): advance(50) signal.turn_on() sim = Simulator() queue = Queue() signal = Signal().turn_off() resource = Resource(1) proc_ordeal = sim.add(ordeal, queue, signal, resource) name_ordeal = proc_ordeal.local.name sim.add(do_resume, proc_ordeal) sim.add(do_pop, queue) sim.add(do_open, signal) sim.run() assert [(logging.DEBUG, 0.0, name_ordeal, "debug"), (logging.INFO, 10.0, name_ordeal, "info"), (logging.WARNING, 15.0, name_ordeal, "warning"), (logging.ERROR, 30.0, "the-process", "error"), (logging.CRITICAL, 50.0, name_ordeal, "critical"), (logging.CRITICAL, 1000.0, name_ordeal, "finish") ] == logger.handlers[0].log
def test_auto_log_resource(auto_logger): def proc(res, name, delay_before, delay_with): local.name = name advance(delay_before) with res.using(): advance(delay_with) resource = Resource(1, name="the-resource") sim = Simulator(name="sim") sim.add(proc, resource, "alpha", 10, 50) sim.add(proc, resource, "beta", 30, 10) sim.run() check_log( auto_logger, (logging.INFO, 0.0, "", "Simulator", "sim", "add", dict(fn=proc, args=(resource, "alpha", 10.0, 50.0), kwargs={})), (logging.INFO, 0.0, "", "Simulator", "sim", "add", dict(fn=proc, args=(resource, "beta", 30.0, 10.0), kwargs={})), (logging.INFO, 0.0, "", "Simulator", "sim", "run", dict(duration=inf)), (logging.INFO, 0.0, "alpha", "Process", "alpha", "advance", dict(delay=10.0)), (logging.INFO, 0.0, "beta", "Process", "beta", "advance", dict(delay=30.0)), (logging.INFO, 10.0, "alpha", "Resource", "the-resource", "take", dict(num_instances=1, free=1)), (logging.INFO, 10.0, "alpha", "Process", "alpha", "advance", dict(delay=50.0)), (logging.INFO, 30.0, "beta", "Resource", "the-resource", "take", dict(num_instances=1, free=0)), (logging.INFO, 30.0, "beta", "Queue", "the-resource-queue", "join", {}), (logging.INFO, 30.0, "beta", "Process", "beta", "pause", {}), (logging.INFO, 60.0, "alpha", "Resource", "the-resource", "release", dict(num_instances=1, keeping=0, free=1)), (logging.INFO, 60.0, "alpha", "Queue", "the-resource-queue", "pop", dict(process="beta")), (logging.INFO, 60.0, "alpha", "Process", "beta", "resume", {}), (logging.INFO, 60.0, "alpha", "Process", "alpha", "die-finish", {}), (logging.INFO, 60.0, "beta", "Process", "beta", "advance", dict(delay=10.0)), (logging.INFO, 70.0, "beta", "Resource", "the-resource", "release", dict(num_instances=1, keeping=0, free=1)), (logging.INFO, 70.0, "beta", "Process", "beta", "die-finish", {}), (logging.INFO, 70.0, "", "Simulator", "sim", "stop", {}))
def proc(resource: Resource) -> None: resource.release() pytest.fail()
def take_M_release_N(resource: Resource, num_take: int, num_release: int) -> None: resource.take(num_take) advance(1.0) resource.release(num_release)
def take_many(resource: Resource, delay: float, log: List[float]) -> None: with resource.using(int(delay)): do_while_holding_resource(delay, log)
def take_release(resource: Resource, delay: float, log: List[float]) -> None: resource.take() do_while_holding_resource(delay, log) resource.release()
from random import Random from greensim import Simulator, advance, add, Resource, now from greensim.progress import track_progress # Time convention: 1.0 == 1 minute # Initial setup. rng = Random() sim = Simulator() resource = Resource(1) # One server for the queue. # Rates of customer arrival and service. RATE_ARRIVAL = 1.0 / 10.0 RATE_SERVICE = 1.0 / 6.0 # Simulation runs until a certain number of customers have been served. num_served = 0 NUM_CLIENTS_STOP = 200000 # Measure total time spent in the system (the *service time*). times_service = [] # Arrival process: start the service of another customer according to a Poisson process. In other words, arrival time # between customers is an exponential random variable of mean the inverse of the arrival rate. The Random class' # expovariate takes the inverse of the intended mean as parameter. def arrival(): while True: advance(rng.expovariate(RATE_ARRIVAL)) add(service)