Commit 9b24f41f0ffc461c5a5136969d6f08a6af38b3ba
1 parent
d3d48015
Add mputils.process() function and reduce code duplication
Showing
9 changed files
with
108 additions
and
113 deletions
cscripts/cslightcrv.py
| @@ -647,20 +647,13 @@ class cslightcrv(ctools.csobservation): | @@ -647,20 +647,13 @@ class cslightcrv(ctools.csobservation): | ||
| 647 | # Write header | 647 | # Write header |
| 648 | self._log_header1(gammalib.TERSE, 'Generate lightcurve') | 648 | self._log_header1(gammalib.TERSE, 'Generate lightcurve') |
| 649 | 649 | ||
| 650 | - # If using multiprocessing | 650 | + # If more than a single thread is requested then use multiprocessing |
| 651 | if self._nthreads > 1: | 651 | if self._nthreads > 1: |
| 652 | 652 | ||
| 653 | - # Create pool of workers | ||
| 654 | - from multiprocessing import Pool | ||
| 655 | - pool = Pool(processes = self._nthreads) | ||
| 656 | - | ||
| 657 | - # Run time bin analysis in parallel with map | 653 | + # Compute time bins |
| 658 | args = [(self, i) for i in range(self._tbins.size())] | 654 | args = [(self, i) for i in range(self._tbins.size())] |
| 659 | - poolresults = pool.map(_multiprocessing_func_wrapper, args) | ||
| 660 | - | ||
| 661 | - # Close pool and join | ||
| 662 | - pool.close() | ||
| 663 | - pool.join() | 655 | + poolresults = mputils.process(self._nthreads, |
| 656 | + _multiprocessing_func_wrapper, args) | ||
| 664 | 657 | ||
| 665 | # Construct results | 658 | # Construct results |
| 666 | results = [] | 659 | results = [] |
cscripts/csphagen.py
| @@ -578,17 +578,10 @@ class csphagen(ctools.csobservation): | @@ -578,17 +578,10 @@ class csphagen(ctools.csobservation): | ||
| 578 | # If there is more than one observation and we use multiprocessing | 578 | # If there is more than one observation and we use multiprocessing |
| 579 | if self._nthreads > 1 and self.obs().size() > 1: | 579 | if self._nthreads > 1 and self.obs().size() > 1: |
| 580 | 580 | ||
| 581 | - # Create pool of workers | ||
| 582 | - from multiprocessing import Pool | ||
| 583 | - pool = Pool(processes = self._nthreads) | ||
| 584 | - | ||
| 585 | - # Run time bin analysis in parallel with map | 581 | + # Compute observations |
| 586 | args = [(self, i) for i in range(self.obs().size())] | 582 | args = [(self, i) for i in range(self.obs().size())] |
| 587 | - poolresults = pool.map(_multiprocessing_func_wrapper, args) | ||
| 588 | - | ||
| 589 | - # Close pool and join | ||
| 590 | - pool.close() | ||
| 591 | - pool.join() | 583 | + poolresults = mputils.process(self._nthreads, |
| 584 | + _multiprocessing_func_wrapper, args) | ||
| 592 | 585 | ||
| 593 | # Construct results | 586 | # Construct results |
| 594 | for i in range(self.obs().size()): | 587 | for i in range(self.obs().size()): |
cscripts/csphasecrv.py
| @@ -493,20 +493,13 @@ class csphasecrv(ctools.csobservation): | @@ -493,20 +493,13 @@ class csphasecrv(ctools.csobservation): | ||
| 493 | # Write header | 493 | # Write header |
| 494 | self._log_header1(gammalib.TERSE, 'Generate phase curve') | 494 | self._log_header1(gammalib.TERSE, 'Generate phase curve') |
| 495 | 495 | ||
| 496 | - # If using multiprocessing | 496 | + # If more than a single thread is requested then use multiprocessing |
| 497 | if self._nthreads > 1: | 497 | if self._nthreads > 1: |
| 498 | 498 | ||
| 499 | - # Create pool of workers | ||
| 500 | - from multiprocessing import Pool | ||
| 501 | - pool = Pool(processes = self._nthreads) | ||
| 502 | - | ||
| 503 | - # Run time bin analysis in parallel with map | 499 | + # Compute phase bins |
| 504 | args = [(self, phbin) for phbin in self._phbins] | 500 | args = [(self, phbin) for phbin in self._phbins] |
| 505 | - poolresults = pool.map(_multiprocessing_func_wrapper, args) | ||
| 506 | - | ||
| 507 | - # Close pool and join | ||
| 508 | - pool.close() | ||
| 509 | - pool.join() | 501 | + poolresults = mputils.process(self._nthreads, |
| 502 | + _multiprocessing_func_wrapper, args) | ||
| 510 | 503 | ||
| 511 | # Construct results | 504 | # Construct results |
| 512 | for i in range(len(self._phbins)): | 505 | for i in range(len(self._phbins)): |
cscripts/cspull.py
| @@ -377,40 +377,34 @@ class cspull(ctools.csobservation): | @@ -377,40 +377,34 @@ class cspull(ctools.csobservation): | ||
| 377 | # Write header | 377 | # Write header |
| 378 | self._log_header1(gammalib.TERSE, 'Generate pull distribution') | 378 | self._log_header1(gammalib.TERSE, 'Generate pull distribution') |
| 379 | 379 | ||
| 380 | - # If using multiprocessing | ||
| 381 | - if self._nthreads > 1: | ||
| 382 | - | ||
| 383 | - # Create pool of workers | ||
| 384 | - from multiprocessing import Pool | ||
| 385 | - pool = Pool(processes = self._nthreads) | ||
| 386 | - | ||
| 387 | - # Run time bin analysis in parallel with map | ||
| 388 | - args = [(self, seed + self['seed'].integer()) | ||
| 389 | - for seed in range(self['ntrials'].integer())] | ||
| 390 | - poolresults = pool.map(_multiprocessing_func_wrapper, args) | 380 | + # Get number of trials |
| 381 | + ntrials = self['ntrials'].integer() | ||
| 391 | 382 | ||
| 392 | - # Close pool and join | ||
| 393 | - pool.close() | ||
| 394 | - pool.join() | 383 | + # Get seed value |
| 384 | + seed = self['seed'].integer() | ||
| 395 | 385 | ||
| 396 | - # Write results | ||
| 397 | - for seed in range(self['ntrials'].integer()): | ||
| 398 | - result = poolresults[seed][0] | ||
| 399 | - ioutils.write_csv_row(self['outfile'].filename().url(), seed, | ||
| 400 | - result['colnames'], result['values']) | ||
| 401 | - self._log_string(gammalib.TERSE, poolresults[seed][1]['log'], False) | 386 | + # If more than a single thread is requested then use multiprocessing |
| 387 | + if self._nthreads > 1: | ||
| 388 | + args = [(self, i + seed) for i in range(ntrials)] | ||
| 389 | + poolresults = mputils.process(self._nthreads, | ||
| 390 | + _multiprocessing_func_wrapper, args) | ||
| 402 | 391 | ||
| 403 | - # Otherwise, loop over trials | ||
| 404 | - else: | 392 | + # Continue with regular processing |
| 393 | + for i in range(ntrials): | ||
| 405 | 394 | ||
| 406 | - for seed in range(self['ntrials'].integer()): | 395 | + # If multiprocessing was used then recover results and put them |
| 396 | + # into the log file | ||
| 397 | + if self._nthreads > 1: | ||
| 398 | + result = poolresults[i][0] | ||
| 399 | + self._log_string(gammalib.TERSE, poolresults[i][1]['log'], False) | ||
| 407 | 400 | ||
| 408 | - # Make a trial and add initial seed | ||
| 409 | - result = self._trial(seed + self['seed'].integer()) | 401 | + # ... otherwise make a trial now |
| 402 | + else: | ||
| 403 | + result = self._trial(i + seed) | ||
| 410 | 404 | ||
| 411 | - # Write out trial result | ||
| 412 | - ioutils.write_csv_row(self['outfile'].filename().url(), seed, | ||
| 413 | - result['colnames'], result['values']) | 405 | + # Write out trial result |
| 406 | + ioutils.write_csv_row(self['outfile'].filename().url(), i, | ||
| 407 | + result['colnames'], result['values']) | ||
| 414 | 408 | ||
| 415 | # Return | 409 | # Return |
| 416 | return | 410 | return |
cscripts/cssens.py
| @@ -715,17 +715,10 @@ class cssens(ctools.csobservation): | @@ -715,17 +715,10 @@ class cssens(ctools.csobservation): | ||
| 715 | # If using multiprocessing | 715 | # If using multiprocessing |
| 716 | if self._nthreads > 1 and self._ebounds.size() > 1: | 716 | if self._nthreads > 1 and self._ebounds.size() > 1: |
| 717 | 717 | ||
| 718 | - # Create pool of workers | ||
| 719 | - from multiprocessing import Pool | ||
| 720 | - pool = Pool(processes = self._nthreads) | ||
| 721 | - | ||
| 722 | - # Run energy bin analysis in parallel with map | 718 | + # Compute phase bins |
| 723 | args = [(self, ieng) for ieng in range(self._ebounds.size())] | 719 | args = [(self, ieng) for ieng in range(self._ebounds.size())] |
| 724 | - poolresults = pool.map(_multiprocessing_func_wrapper, args) | ||
| 725 | - | ||
| 726 | - # Close pool and join | ||
| 727 | - pool.close() | ||
| 728 | - pool.join() | 720 | + poolresults = mputils.process(self._nthreads, |
| 721 | + _multiprocessing_func_wrapper, args) | ||
| 729 | 722 | ||
| 730 | # Construct results | 723 | # Construct results |
| 731 | for ieng in range(self._ebounds.size()): | 724 | for ieng in range(self._ebounds.size()): |
cscripts/csspec.py
| @@ -771,20 +771,13 @@ class csspec(ctools.csobservation): | @@ -771,20 +771,13 @@ class csspec(ctools.csobservation): | ||
| 771 | # Initialise results | 771 | # Initialise results |
| 772 | results = [] | 772 | results = [] |
| 773 | 773 | ||
| 774 | - # If using multiprocessing | 774 | + # If more than a single thread is requested then use multiprocessing |
| 775 | if self._nthreads > 1: | 775 | if self._nthreads > 1: |
| 776 | 776 | ||
| 777 | - # Create pool of workers | ||
| 778 | - from multiprocessing import Pool | ||
| 779 | - pool = Pool(processes = self._nthreads) | ||
| 780 | - | ||
| 781 | - # Run energy bin analysis in parallel with map | 777 | + # Compute energy bins |
| 782 | args = [(self, i) for i in range(self._ebounds.size())] | 778 | args = [(self, i) for i in range(self._ebounds.size())] |
| 783 | - poolresults = pool.map(_multiprocessing_func_wrapper, args) | ||
| 784 | - | ||
| 785 | - # Close pool and join | ||
| 786 | - pool.close() | ||
| 787 | - pool.join() | 779 | + poolresults = mputils.process(self._nthreads, |
| 780 | + _multiprocessing_func_wrapper, args) | ||
| 788 | 781 | ||
| 789 | # Construct results | 782 | # Construct results |
| 790 | for i in range(self._ebounds.size()): | 783 | for i in range(self._ebounds.size()): |
cscripts/cstsdist.py
| @@ -329,38 +329,30 @@ class cstsdist(ctools.csobservation): | @@ -329,38 +329,30 @@ class cstsdist(ctools.csobservation): | ||
| 329 | # Write header | 329 | # Write header |
| 330 | self._log_header1(gammalib.TERSE, 'Generate TS distribution') | 330 | self._log_header1(gammalib.TERSE, 'Generate TS distribution') |
| 331 | 331 | ||
| 332 | - # If using multiprocessing | ||
| 333 | - if self._nthreads > 1: | ||
| 334 | - | ||
| 335 | - # Create pool of workers | ||
| 336 | - from multiprocessing import Pool | ||
| 337 | - pool = Pool(processes = self._nthreads) | ||
| 338 | - | ||
| 339 | - # Run time bin analysis in parallel with map | ||
| 340 | - args = [(self, seed) for seed in range(self['ntrials'].integer())] | ||
| 341 | - poolresults = pool.map(_multiprocessing_func_wrapper, args) | 332 | + # Get number of trials |
| 333 | + ntrials = self['ntrials'].integer() | ||
| 342 | 334 | ||
| 343 | - # Close pool and join | ||
| 344 | - pool.close() | ||
| 345 | - pool.join() | ||
| 346 | - | ||
| 347 | - # Write results | ||
| 348 | - for seed in range(self['ntrials'].integer()): | ||
| 349 | - result = poolresults[seed][0] | ||
| 350 | - ioutils.write_csv_row(self['outfile'].filename().url(), seed, | ||
| 351 | - result['colnames'], result['values']) | ||
| 352 | - self._log_string(gammalib.TERSE, poolresults[seed][1]['log'], False) | 335 | + # If more than a single thread is requested then use multiprocessing |
| 336 | + if self._nthreads > 1: | ||
| 337 | + args = [(self, i) for i in range(ntrials)] | ||
| 338 | + poolresults = mputils.process(self._nthreads, | ||
| 339 | + _multiprocessing_func_wrapper, args) | ||
| 353 | 340 | ||
| 354 | - # Otherwise, loop over trials | ||
| 355 | - else: | 341 | + # Continue with regular processing |
| 342 | + for i in range(ntrials): | ||
| 356 | 343 | ||
| 357 | - for seed in range(self['ntrials'].integer()): | 344 | + # If multiprocessing was used then recover results and put them |
| 345 | + # into the log file | ||
| 346 | + if self._nthreads > 1: | ||
| 347 | + result = poolresults[i][0] | ||
| 348 | + self._log_string(gammalib.TERSE, poolresults[i][1]['log'], False) | ||
| 358 | 349 | ||
| 359 | - # Make a trial | ||
| 360 | - result = self._trial(seed) | 350 | + # ... otherwise make a trial now |
| 351 | + else: | ||
| 352 | + result = self._trial(i) | ||
| 361 | 353 | ||
| 362 | - # Write out trial result | ||
| 363 | - ioutils.write_csv_row(self['outfile'].filename().url(), seed, | 354 | + # Write out trial result |
| 355 | + ioutils.write_csv_row(self['outfile'].filename().url(), i, | ||
| 364 | result['colnames'], result['values']) | 356 | result['colnames'], result['values']) |
| 365 | 357 | ||
| 366 | # Return | 358 | # Return |
cscripts/mputils.py
| @@ -20,12 +20,12 @@ | @@ -20,12 +20,12 @@ | ||
| 20 | import gammalib | 20 | import gammalib |
| 21 | 21 | ||
| 22 | 22 | ||
| 23 | -# ==================== # | ||
| 24 | -# Number of processes # | ||
| 25 | -# ==================== # | 23 | +# ====================== # |
| 24 | +# Get number of threads # | ||
| 25 | +# ====================== # | ||
| 26 | def nthreads(cls): | 26 | def nthreads(cls): |
| 27 | """ | 27 | """ |
| 28 | - Determines the number of parallel processes to use. | 28 | + Determines the number of parallel processes to use |
| 29 | 29 | ||
| 30 | The number is based on the user parameter "nthreads" and the availability | 30 | The number is based on the user parameter "nthreads" and the availability |
| 31 | of the multiprocessing module. | 31 | of the multiprocessing module. |
| @@ -38,7 +38,7 @@ def nthreads(cls): | @@ -38,7 +38,7 @@ def nthreads(cls): | ||
| 38 | Returns | 38 | Returns |
| 39 | ------- | 39 | ------- |
| 40 | nthreads : int | 40 | nthreads : int |
| 41 | - Number of parallel processes | 41 | + Number of threads |
| 42 | """ | 42 | """ |
| 43 | # Log multiprocessing configuration | 43 | # Log multiprocessing configuration |
| 44 | cls._log_header1(gammalib.NORMAL, 'Multiprocessing') | 44 | cls._log_header1(gammalib.NORMAL, 'Multiprocessing') |
| @@ -69,3 +69,41 @@ def nthreads(cls): | @@ -69,3 +69,41 @@ def nthreads(cls): | ||
| 69 | 69 | ||
| 70 | # Return number of processes to be used | 70 | # Return number of processes to be used |
| 71 | return nthreads | 71 | return nthreads |
| 72 | + | ||
| 73 | + | ||
| 74 | +# ============================ # | ||
| 75 | +# Execute function in parallel # | ||
| 76 | +# ============================ # | ||
| 77 | +def process(nthreads, function, args): | ||
| 78 | + """ | ||
| 79 | + Execute function in parallel | ||
| 80 | + | ||
| 81 | + Parameters | ||
| 82 | + ---------- | ||
| 83 | + nthreads : int | ||
| 84 | + Number of parallel threads | ||
| 85 | + function : Python function | ||
| 86 | + Function to be executed in parallel | ||
| 87 | + args : list of tuples | ||
| 88 | + Function arguments for each evaluation | ||
| 89 | + | ||
| 90 | + Returns | ||
| 91 | + ------- | ||
| 92 | + results : list of dicts | ||
| 93 | + List of function evaluation results | ||
| 94 | + """ | ||
| 95 | + # Import Pool module from multiprocessing module | ||
| 96 | + from multiprocessing import Pool | ||
| 97 | + | ||
| 98 | + # Create a pool of processes | ||
| 99 | + pool = Pool(processes=nthreads) | ||
| 100 | + | ||
| 101 | + # Run function in parallel | ||
| 102 | + results = pool.map(function, args) | ||
| 103 | + | ||
| 104 | + # Close pool and join | ||
| 105 | + pool.close() | ||
| 106 | + pool.join() | ||
| 107 | + | ||
| 108 | + # Return results | ||
| 109 | + return results |
test/test_ctbutterfly.py
| @@ -123,6 +123,12 @@ class Test(test): | @@ -123,6 +123,12 @@ class Test(test): | ||
| 123 | # Check result file | 123 | # Check result file |
| 124 | self._check_result_file('ctbutterfly_py1.dat') | 124 | self._check_result_file('ctbutterfly_py1.dat') |
| 125 | 125 | ||
| 126 | + # Check CSV result | ||
| 127 | + self.test_value(butterfly.butterfly().nrows(), 100, | ||
| 128 | + 'Check for 100 rows in CSV file') | ||
| 129 | + self.test_value(butterfly.butterfly().ncols(), 4, | ||
| 130 | + 'Check for 4 columns in CSV file') | ||
| 131 | + | ||
| 126 | # Set-up ctbutterfly | 132 | # Set-up ctbutterfly |
| 127 | butterfly = ctools.ctbutterfly() | 133 | butterfly = ctools.ctbutterfly() |
| 128 | butterfly['inobs'] = self._events | 134 | butterfly['inobs'] = self._events |