core.py 3.3KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
  1. # coding: utf-8
  2. import time
  3. from synergine2.base import BaseObject
  4. from synergine2.config import Config
  5. from synergine2.cycle import CycleManager
  6. from synergine2.log import SynergineLogger
  7. from synergine2.simulation import Simulation
  8. from synergine2.terminals import TerminalManager
  9. from synergine2.terminals import TerminalPackage
  10. from synergine2.utils import time_it
  11. class Core(BaseObject):
  12. def __init__(
  13. self,
  14. config: Config,
  15. logger: SynergineLogger,
  16. simulation: Simulation,
  17. cycle_manager: CycleManager,
  18. terminal_manager: TerminalManager=None,
  19. cycles_per_seconds: float=1.0,
  20. ):
  21. self.config = config
  22. self.logger = logger
  23. self.simulation = simulation
  24. self.cycle_manager = cycle_manager
  25. self.terminal_manager = terminal_manager or TerminalManager(config, logger, [])
  26. self._loop_delta = 1./cycles_per_seconds
  27. self._current_cycle_start_time = None
  28. def run(self):
  29. self.logger.info('Run core')
  30. try:
  31. self.terminal_manager.start()
  32. start_package = TerminalPackage(
  33. subjects=self.simulation.subjects,
  34. )
  35. self.logger.info('Send start package to terminals')
  36. self.terminal_manager.send(start_package)
  37. while True:
  38. self._start_cycle()
  39. events = []
  40. packages = self.terminal_manager.receive()
  41. for package in packages:
  42. events.extend(self.cycle_manager.apply_actions(
  43. simulation_actions=package.simulation_actions,
  44. subject_actions=package.subject_actions,
  45. ))
  46. with time_it() as elapsed_time:
  47. events.extend(self.cycle_manager.next())
  48. # TODO: There is a problem with logger: when "pickled" we remove it's handler
  49. self.logger.info('Cycle duration: {}s'.format(elapsed_time.get_final_time()))
  50. print('Cycle duration: {}s'.format(elapsed_time.get_final_time()))
  51. cycle_package = TerminalPackage(
  52. events=events,
  53. add_subjects=self.simulation.subjects.adds,
  54. remove_subjects=self.simulation.subjects.removes,
  55. is_cycle=True,
  56. )
  57. self.terminal_manager.send(cycle_package)
  58. # Reinitialize these list for next cycle
  59. self.simulation.subjects.adds = []
  60. self.simulation.subjects.removes = []
  61. self._end_cycle()
  62. except KeyboardInterrupt:
  63. pass # Just stop while
  64. self.terminal_manager.stop()
  65. def _start_cycle(self):
  66. time_ = time.time()
  67. self.logger.info('Start cycle at time {}'.format(time_))
  68. self._current_cycle_start_time = time_
  69. def _end_cycle(self) -> None:
  70. """
  71. Make a sleep if cycle duration take less time of wanted (see
  72. cycles_per_seconds constructor parameter)
  73. """
  74. time_ = time.time()
  75. self.logger.info('End of cycle at time {}'.format(time_))
  76. cycle_duration = time_ - self._current_cycle_start_time
  77. sleep_time = self._loop_delta - cycle_duration
  78. self.logger.info('Sleep time is {}'.format(sleep_time))
  79. if sleep_time > 0:
  80. time.sleep(sleep_time)