0

I am writing a scientific software that performs image analysis by measuring beam intensities within circular region of interests (ROIs or spots). The code has a Tracker that allows for following the beams as they move. For each image, there are usually 3-12 spots, and it would be great to have a way to parallelize the part of code that performs the analysis. The relevant code follows:

class Worker(QObject):
""" Worker that manages the spots."""

    def __init__(self, spots, center, energy, parent=None):
        super(Worker, self).__init__(parent)
        #### setup widgets ####
        self.plotwid = PlotWidget()

        # spots_map:
        # - key: spot
        # - value: SpotModel, Tracker
        self.spots_map = {}

        # THIS SHOULD BE PARALLELIZED
        for spot in spots:
            pos = spot.scenePos()
            if center:
                tracker = Tracker(pos.x(), pos.y(), spot.radius(), energy, center.x(), center.y(),
                            input_precision = config.Tracking_inputPrecision,
                            window_scaling = config.Tracking_windowScalingOn)
            else:
                tracker = Tracker(pos.x(), pos.y(), spot.radius(), energy,
                            input_precision = config.Tracking_inputPrecision,
                            window_scaling = config.Tracking_windowScalingOn)
            self.spots_map[spot] = (QSpotModel(self), tracker)

        for view, tup in self.spots_map.iteritems():
            # view = QGraphicsSpotItem, tup = (QSpotModel, tracker) -> tup[0] = QSpotModel
            self.connect(tup[0], SIGNAL("positionChanged"), view.onPositionChange)
            self.connect(tup[0], SIGNAL("radiusChanged"), view.onRadiusChange)

This function is called upon every time an image is opened. A tyical acquisition deals with hundreds of images, and for each this funciton is called. Thanks in advance for any help.

Update 1: Thanks for the suggestions below a few tests. First: Multithreading, with same speed as the original:

class thread_it(Thread):
    def __init__ (self,param):
        Thread.__init__(self)
        self.param = param
    def run(self):
        mutex.acquire()
        output.append(calc_stuff(self.param))
        mutex.release()

class Worker(QObject):
     """ Worker that manages the spots."""

     def __init__(self, spots, center, energy, parent=None):
         super(Worker, self).__init__(parent)

         threads = []
         output = []
         mutex = thread.allocate_lock()

         self.spots_map = {}
         for spot in spots:
             current = thread_it(self.run(spot, center, energy))
             threads.append(current)
             current.start()

         for t in threads:
              t.join()

      def run(self, spot, center, energy):
         pos = spot.scenePos()
         if center:
             tracker = Tracker(pos.x(), pos.y(), spot.radius(), energy, center.x(), center.y(),
                      input_precision = config.Tracking_inputPrecision,
                      window_scaling = config.Tracking_windowScalingOn)
         else:
             tracker = Tracker(pos.x(), pos.y(), spot.radius(), energy,
                              input_precision = config.Tracking_inputPrecision,
                              window_scaling = config.Tracking_windowScalingOn)
         self.spots_map[spot] = (QSpotModel(self), tracker)

This makes no difference in terms of performance.

Update 2: Using joblib:

class Worker(QObject):
    """ Worker that manages the spots."""

    def __init__(self, spots, center, energy, parent=None):
        super(Worker, self).__init__(parent)
        self.spots_map = {}

        for spot in spots:
            Parallel(n_jobs=2)(delayed(self.run)(spot, center, energy) for spot in spots)

        for view, tup in self.spots_map.iteritems():

             self.connect(tup[0], SIGNAL("positionChanged"), view.onPositionChange)
             self.connect(tup[0], SIGNAL("radiusChanged"), view.onRadiusChange)


     def run(self, spot, center, energy):
         pos = spot.scenePos()
         if center:
             tracker = Tracker(pos.x(), pos.y(), spot.radius(), energy, center.x(), center.y(),
                      input_precision = config.Tracking_inputPrecision,
                      window_scaling = config.Tracking_windowScalingOn)
         else:
             tracker = Tracker(pos.x(), pos.y(), spot.radius(), energy,
                              input_precision = config.Tracking_inputPrecision,
                              window_scaling = config.Tracking_windowScalingOn)
         self.spots_map[spot] = (QSpotModel(self), tracker)

Gives this error:

  File "/Users/feranick/Desktop/easyleed/source/easyleed/gui.py", line 1189, in __init__
  Parallel(n_jobs=2)(delayed(self.run)(spot, center, energy) for spot in spots)
  File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/joblib/parallel.py", line 652, in __call__
  for function, args, kwargs in iterable:
  File "/Users/feranick/Desktop/easyleed/source/easyleed/gui.py", line 1189, in <genexpr>
  Parallel(n_jobs=2)(delayed(self.run)(spot, center, energy) for spot in spots)
  File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/joblib/parallel.py", line 120, in delayed
   pickle.dumps(function)
  File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/copy_reg.py", line 70, in _reduce_ex
  raise TypeError, "can't pickle %s objects" % base.__name__
  TypeError: can't pickle instancemethod objects

I am at loss here. Any help is appreciated.

feranick
  • 1
  • 1
  • [how do I parallelize a simple python loop?](http://stackoverflow.com/questions/9786102/how-do-i-parallelize-a-simple-python-loop) – wwii Oct 10 '14 at 16:44
  • This package looks promising [Embarrassingly parallel for loops](https://pythonhosted.org/joblib/parallel.html#) – wwii Oct 11 '14 at 11:58

0 Answers0