/tests/zzz_deprecated_unmaintained/parallel/localstep-benchmark/LocalStepUtil_ParallelIPC.py

https://github.com/bnpy/bnpy · Python · 110 lines · 77 code · 11 blank · 22 comment · 4 complexity · 410c34c9b6a190d88e6f2e55d9cf69f9 MD5 · raw file

  1. import multiprocessing
  2. import numpy as np
  3. import time
  4. import bnpy
  5. from RunBenchmark import sliceGenerator
  6. def calcLocalParamsAndSummarize(
  7. JobQ, ResultQ, Data, hmodel, nWorker=0,
  8. LPkwargs=dict(),
  9. **kwargs):
  10. """ Execute processed by workers in parallel.
  11. """
  12. # MAP step
  13. # Create several tasks (one per worker) and add to job queue
  14. for start, stop in sliceGenerator(Data, nWorker):
  15. Dslice = Data.select_subset_by_mask(
  16. np.arange(start,stop, dtype=np.int32))
  17. JobQ.put((Dslice, hmodel, LPkwargs))
  18. # Pause at this line until all jobs are marked complete.
  19. JobQ.join()
  20. # REDUCE step
  21. # Aggregate results across across all workers
  22. SS, telapsed_max = ResultQ.get()
  23. while not ResultQ.empty():
  24. SSslice, telapsed_cur = ResultQ.get()
  25. SS += SSslice
  26. telapsed_max = np.maximum(telapsed_max, telapsed_cur)
  27. return SS, telapsed_max
  28. def setUpWorkers(nWorker=1, verbose=0, nRepsForMinDuration=1, **kwargs):
  29. ''' Create queues and launch all workers.
  30. Returns
  31. -------
  32. JobQ
  33. ResultQ
  34. '''
  35. # Create a JobQ (to hold tasks to be done)
  36. # and a ResultsQ (to hold results of completed tasks)
  37. manager = multiprocessing.Manager()
  38. JobQ = manager.Queue()
  39. ResultQ = manager.Queue()
  40. # Launch desired number of worker processes
  41. # We don't need to store references to these processes,
  42. # We can get everything we need from JobQ and ResultsQ
  43. for uid in range(nWorker):
  44. workerProcess = Worker_IPCData_IPCModel(
  45. uid, JobQ, ResultQ,
  46. nReps=nRepsForMinDuration,
  47. verbose=verbose)
  48. workerProcess.start()
  49. return JobQ, ResultQ
  50. def tearDownWorkers(JobQ=None, ResultQ=None, nWorker=1, **kwargs):
  51. ''' Shutdown pool of workers.
  52. '''
  53. for workerID in range(nWorker):
  54. # Passing None to JobQ is shutdown signal
  55. JobQ.put(None)
  56. time.sleep(0.1) # let workers all shut down before we quit
  57. class Worker_IPCData_IPCModel(multiprocessing.Process):
  58. ''' Single "worker" process that processes tasks delivered via queues.
  59. Attributes
  60. ----------
  61. JobQ : multiprocessing.Queue
  62. ResultQ : multiprocessing.Queue
  63. '''
  64. def __init__(self, uid, JobQ, ResultQ, verbose=0, nReps=1):
  65. ''' Create single worker process, linked to provided queues.
  66. '''
  67. super(type(self), self).__init__() # Required super constructor call
  68. self.uid = uid
  69. self.JobQ = JobQ
  70. self.ResultQ = ResultQ
  71. self.verbose = verbose
  72. self.nReps = nReps
  73. def run(self):
  74. ''' Perform calcLocalParamsAndSummarize on jobs in JobQ.
  75. Post Condition
  76. --------------
  77. After each inner loop, SuffStatBag is written to ResultQ.
  78. '''
  79. # Construct iterator with sentinel value of None (for termination)
  80. jobIterator = iter(self.JobQ.get, None)
  81. for jobArgs in jobIterator:
  82. Dslice, hmodel, LPkwargs = jobArgs
  83. tstart = time.time()
  84. for rep in range(self.nReps):
  85. LPslice = hmodel.calc_local_params(Dslice, **LPkwargs)
  86. SSslice = hmodel.get_global_suff_stats(
  87. Dslice, LPslice, **LPkwargs)
  88. twork = time.time() - tstart
  89. self.ResultQ.put((SSslice, twork))
  90. self.JobQ.task_done()