queue.py 3.0 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576
  1. from pypdevs.DEVS import AtomicDEVS
  2. # Define the state of the queue as a structured object
  3. class QueueState:
  4. def __init__(self, outputs):
  5. # Keep a list of all idle processors
  6. self.idle_procs = list(range(outputs))
  7. # Keep a list that is the actual queue data structure
  8. self.queue = []
  9. # Keep the process that is currently being processed
  10. self.processing = None
  11. # Time remaining for this event
  12. self.remaining_time = float("inf")
  13. class Queue(AtomicDEVS):
  14. def __init__(self, outputs):
  15. AtomicDEVS.__init__(self, "Queue")
  16. # Fix the time needed to process a single event
  17. self.processing_time = 1.0
  18. self.state = QueueState(outputs)
  19. # Create 'outputs' output ports
  20. # 'outputs' is a structural parameter!
  21. self.out_proc = []
  22. for i in range(outputs):
  23. self.out_proc.append(self.addOutPort("proc_%i" % i))
  24. # Add the other ports: incoming events and finished event
  25. self.in_event = self.addInPort("in_event")
  26. self.in_finish = self.addInPort("in_finish")
  27. def extTransition(self, inputs):
  28. # Update the remaining time of this job
  29. self.state.remaining_time -= self.elapsed
  30. # Several possibilities
  31. if self.in_finish in inputs:
  32. # Processing a "finished" event, so mark proc as idle
  33. self.state.idle_procs.append(inputs[self.in_finish])
  34. if not self.state.processing and self.state.queue:
  35. # Process first task in queue
  36. self.state.processing = self.state.queue.pop(0)
  37. self.state.remaining_time = self.processing_time
  38. elif self.in_event in inputs:
  39. # Processing an incoming event
  40. if self.state.idle_procs and not self.state.processing:
  41. # Process when idle processors
  42. self.state.processing = inputs[self.in_event]
  43. self.state.remaining_time = self.processing_time
  44. else:
  45. # No idle processors, so queue it
  46. self.state.queue.append(inputs[self.in_event])
  47. return self.state
  48. def timeAdvance(self):
  49. # Just return the remaining time for this event (or infinity else)
  50. return self.state.remaining_time
  51. def outputFnc(self):
  52. # Output the event to the processor
  53. port = self.out_proc[self.state.idle_procs[0]]
  54. return {port: self.state.processing}
  55. def intTransition(self):
  56. # Is only called when we are outputting an event
  57. # Pop the first idle processor and clear processing event
  58. self.state.idle_procs.pop(0)
  59. if self.state.queue and self.state.idle_procs:
  60. # There are still queued elements, so continue
  61. self.state.processing = self.state.queue.pop(0)
  62. self.state.remaining_time = self.processing_time
  63. else:
  64. # No events left to process, so become idle
  65. self.state.processing = None
  66. self.state.remaining_time = float("inf")
  67. return self.state