You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

165 lines
4.5 KiB

  1. import pathlib as pl
  2. import json
  3. import os
  4. import multiprocessing
  5. import threading
  6. from . import batch
  7. class Plan:
  8. def __init__(self, experiment=None, lock=None):
  9. self.experiment = None
  10. self.file = None
  11. self.pending_instances = []
  12. self.assigned_instances = []
  13. self.__lock = threading.Lock() if lock == None else lock
  14. if experiment:
  15. self.create(experiment)
  16. def create(self, experiment):
  17. self.experiment = pl.Path(experiment).resolve()
  18. self.__set_file()
  19. if self.__is_finished():
  20. self.__create()
  21. else:
  22. self.__load()
  23. def __create(self):
  24. content = self.__create_content()
  25. self.pending_instances = content["pending"]
  26. self.iterations_left = content["iterations_left"]
  27. with self.__lock:
  28. self.__update_file()
  29. def __create_content(self, iterations_left = None):
  30. content = {}
  31. with open(self.experiment, "r") as expf:
  32. exp_obj = json.loads(expf.read())
  33. instances = batch.load(pl.Path(exp_obj["batch"]).resolve())
  34. if iterations_left == None:
  35. if "iterations" in exp_obj:
  36. iterations_left = exp_obj["iterations"] - 1
  37. else:
  38. iterations_left = 0
  39. content["pending"] = instances
  40. content["iterations_left"] = iterations_left
  41. return content
  42. def __set_file(self):
  43. if self.experiment == None:
  44. self.file = None
  45. else:
  46. exp_path = pl.Path(self.experiment)
  47. self.file = exp_path.parent / (exp_path.stem + ".plan")
  48. def __load(self):
  49. self.pending_instances = []
  50. self.assigned_instances = []
  51. if not self.file.is_file():
  52. return
  53. with open(self.file, "r") as pfile:
  54. content = json.loads(pfile.read())
  55. if "assigned" in content:
  56. self.assigned_instances = content["assigned"]
  57. if "pending" in content:
  58. self.pending_instances = content["pending"]
  59. if "iterations_left" in content:
  60. self.iterations_left = content["iterations_left"]
  61. def __is_finished(self):
  62. return False if self.file.is_file() else True
  63. def next(self):
  64. with self.__lock:
  65. self.__load()
  66. if len(self.pending_instances) == 0:
  67. if self.iterations_left > 0:
  68. self.__load_next_iteration()
  69. else:
  70. return None
  71. next_instance = self.pending_instances.pop()
  72. self.assigned_instances.append(next_instance)
  73. self.__update_file()
  74. return next_instance
  75. def done_with(self, instance):
  76. with self.__lock:
  77. self.__load()
  78. if instance in self.assigned_instances:
  79. self.assigned_instances.remove(instance)
  80. self.__update_file()
  81. def __update_file(self):
  82. content = {}
  83. all_done = True
  84. content["iterations_left"] = self.iterations_left
  85. if len(self.assigned_instances) > 0:
  86. content["assigned"] = self.assigned_instances
  87. all_done = False
  88. if len(self.pending_instances) > 0:
  89. content["pending"] = self.pending_instances
  90. all_done = False
  91. if all_done:
  92. if self.iterations_left > 0:
  93. self.__load_next_iteration()
  94. elif self.file.is_file():
  95. self.file.unlink()
  96. else:
  97. self.__write_content(content)
  98. def __load_next_iteration(self):
  99. content = self.__create_content(self.iterations_left - 1)
  100. self.pending_instances = content["pending"]
  101. self.iterations_left = content["iterations_left"]
  102. self.__write_content(content)
  103. def __write_content(self, content):
  104. if "assigned" in content:
  105. content["assigned"][:] = map(str, content["assigned"])
  106. if "pending" in content:
  107. content["pending"][:] = map(str, content["pending"])
  108. with open(self.file, "w") as pfile:
  109. pfile.write(json.dumps(content))
  110. def delete(self):
  111. with self.__lock:
  112. self.__load()
  113. self.pending_instances.extend(self.assigned_instances)
  114. self.assigned_instances = []
  115. self.__update_file()