def pausing(): nonlocal counter advance(1.0) counter += 1 pause() advance(1.0) counter += 1
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"))
def service(): global num_served time_start = now() with resource.using(): advance(rng.expovariate(RATE_SERVICE)) times_service.append(now() - time_start) num_served += 1
def track_progress(measure: MeasureProgress, target: MetricProgress, interval_check: float, capture_maybe: Optional[CaptureProgress] = None) -> None: """ Tracks progress against a certain end condition of the simulation (for instance, a certain duration on the simulated clock), reporting this progress as the simulation chugs along. Stops the simulation once the target has been reached. By default, the progress is reported as printout on standard output, in a manner that works best for digital terminals. """ def measure_to_target() -> MeasureComparison: return list(zip(measure(), target)) def is_finished(progress: MeasureComparison) -> bool: return all(p >= t for p, t in progress) capture = capture_maybe or capture_print() rt_started = now_real() while True: advance(interval_check) rt_elapsed = now_real() - rt_started progress = measure_to_target() ratio_progress_min = min(m / t for m, t in progress) if ratio_progress_min == 0.0: rt_total_projected = inf else: rt_total_projected = rt_elapsed / ratio_progress_min capture(ratio_progress_min, rt_total_projected - rt_elapsed, progress) if is_finished(progress): stop() break
def process(res): local.name = "proc" res.take(2) advance(10) res.take(3) advance(10) res.release(5)
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 agent_main_queue(): while True: if main_queue.is_empty(): debug(f"MQA waiting for travelers") traveler_enters_main_queue.turn_off().wait() info(f"MQA ready") # Is there a belt where 10 people or less are standing? while True: debug("MQA checks belts -- " + " ".join(f"{b.num}:{b.num_standing}" for b in belts)) belts_available = [belt for belt in belts if belt.num_standing <= LIMIT_TRAVELERS_BELT_AVAILABLE] if len(belts_available) > 0: break # No belt available? Wait for some passengers to leave. debug(f"MQA waiting for a belt to free up") traveler_exits_belt.turn_off().wait() # Assign the least populated suitable belt to the next 5 passengers. belt_best = min(belts_available, key=lambda b: b.num_standing) for _ in range(NUM_TRAVELERS_PER_BATCH): if main_queue.is_empty(): break traveler_next = main_queue.peek() info(f"MQA ushers traveler {traveler_next.local.name} towards belt {belt_best.num}") traveler_next.local.belt = belt_best main_queue.pop() # Let travelers walk over to their belt before addressing the next batch. advance(0.0)
def layovers(): while True: advance(next(interval_layover)) num_passengers = next(num_passengers_layover) info(f"Layover plane with {num_passengers}") for n in range(num_passengers): add(traveler)
def _work_then_break(self) -> None: while True: advance(next(agent_time_work)) info(f"Agents on belt {self.num} going on BREAK") self._agents_working.turn_off() advance(next(agent_time_break)) info(f"Agents on belt {self.num} coming back to work") self._agents_working.turn_on()
def just_advance(name, delay, log): try: local.name = name advance(delay) except greenlet.GreenletExit: log.append(local.name + " EXIT") finally: log.append(local.name + " finish")
def main(ll): try: ll.append(0) advance(15.0) ll.append(1) except Interrupt: ll.append(10) advance(5.0) ll.append(2)
def wait_for(signal: Signal, times_expected: List[float], delay_between: float, log: List[float] = []): for expected in times_expected: advance(delay_between) signal.wait() assert pytest.approx(expected) == now() log.append(now())
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 traverse(self) -> None: # Invoked by crossing passengers in order to get through their luggage and body scan. me = local.name if self._num_standing == 0: period_empty = now() - self._moment_empty self._time_empty += period_empty debug(f"Belt {self.num} -- Empty period: {period_empty:.1f} -- Time empty: {self.time_empty:.1f}") self._num_standing += 1 info(f"Traveler {me} entering belt {self.num}; now {self.num_standing} travelers here") # Prepare for check. advance(next(traveler_preparation)) # Wait for an agent to beckon. info(f"Traveler {me} (belt {self.num}) prepared and ready for processing") self._traveler_ready.turn_on() self._travelers_waiting.join() with local.agent.using(): # Make agent busy with me. # Administer scan or patdown. agent_name = Process.current().local.agent_name processing_type = next(traveler_processing_type) info(f"Traveler {me} processed by agent {agent_name}: {processing_type}") advance(next(traveler_processing_time[processing_type])) info(f"Traveler {me} (belt {self.num}) buckling back up") advance(next(traveler_preparation)) self._num_standing -= 1 if self._num_standing == 0: debug(f"Belt {self.num} now empty") self._moment_empty = now()
def process(): advance(5)
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 interrupter(main): advance(10.1) main.interrupt()
def turn_on() -> None: advance(25.0) sigs[0].turn_on()
def do_while_holding_resource(delay: float, log: List[float]): advance(delay) log.append(now())
def turn_on(): advance(20.0) signal.turn_on()
def enabler(delay: float, sig: Signal) -> None: advance(delay) sig.turn_on()
def main(ll): for n in range(4): t = n * 5.0 ll.append(t) advance(t)
def turn_on(delay: float, signal: Signal) -> None: advance(delay) signal.turn_on()
def pop(): while len(queue) > 0: advance(50) queue.pop()
def would_pop(): nonlocal result advance(20.0) queue.pop() result += 1
def dequeueing(queue, delay): advance(delay) while not queue.is_empty(): advance(1.0) queue.pop()
def proc(delay): advance(delay) log.append(now()) add(proc, delay * 2.0)
def sleeper(interval, rt_delay): while True: advance(interval)
def check_tracker(): advance(150) assert has_tracker(sim, tracker)
def queuer(name: int, queue: Queue, log: List[int], delay: float): local.name = name advance(delay) queue.join() log.append(name)