class_docstr: Class for ultra-simple inline parallelization on multi-core CPUs
  
  Example::
  
      ## Here is the serial (single-process) task:
      
      tasks = [1, 2, 4, 8]
      results = []
      for task in tasks:
          result = processTask(task)
          results.append(result)
      print(results)
      
      
      ## Here is the parallelized version:
      
      tasks = [1, 2, 4, 8]
      results = []
      with Parallelize(tasks, workers=4, results=results) as tasker:
          for task in tasker:
              result = processTask(task)
              tasker.results.append(result)
      print(results)
      
      
  The only major caveat is that *result* in the example above must be picklable,
  since it is automatically sent via pipe back to the parent process.
class_docstr_tok: ["Class","for","ultra-simple","inline","parallelization","on","multi-core","CPUs","Example",":",":","#","#","Here","is","the","serial","(","single-process",")","task",":","tasks","=","[","1",",","2",",","4",",","8","]","results","=","[","]","for","task","in","tasks",":","result","=","processTask","(","task",")","results.append","(","result",")","print","(","results",")","#","#","Here","is","the","parallelized","version",":","tasks","=","[","1",",","2",",","4",",","8","]","results","=","[","]","with","Parallelize","(","tasks",",","workers=4",",","results=results",")","as","tasker",":","for","task","in","tasker",":","result","=","processTask","(","task",")","tasker.results.append","(","result",")","print","(","results",")","The","only","major","caveat","is","that","*","result","*","in","the","example","above","must","be","picklable",",","since","it","is","automatically","sent","via","pipe","back","to","the","parent","process","."]
code: def runParallel(self):
      self.childs = []
  
      ## break up tasks into one set per worker
      workers = self.workers
      chunks = [[] for i in range(workers)]
      i = 0
      for i in range(len(self.tasks)):
          chunks[i % workers].append(self.tasks[i])
  
      ## fork and assign tasks to each worker
      for i in range(workers):
          proc = ForkedProcess(
              target=None, preProxy=self.kwds, randomReseed=self.reseed
          )
          if not proc.isParent:
              self.proc = proc
              return Tasker(self, proc, chunks[i], proc.forkedProxies)
          else:
              self.childs.append(proc)
  
      ## Keep track of the progress of each worker independently.
      self.progress = dict([(ch.childPid, []) for ch in self.childs])
      ## for each child process, self.progress[pid] is a list
      ## of task indexes. The last index is the task currently being
      ## processed; all others are finished.
  
      try:
          if self.showProgress:
              self.progressDlg.__enter__()
              self.progressDlg.setMaximum(len(self.tasks))
          ## process events from workers until all have exited.
  
          activeChilds = self.childs[:]
          self.exitCodes = []
          pollInterval = 0.01
          while len(activeChilds) > 0:
              waitingChildren = 0
              rem = []
              for ch in activeChilds:
                  try:
                      n = ch.processRequests()
                      if n > 0:
                          waitingChildren += 1
                  except ClosedError:
                      # print ch.childPid, 'process finished'
                      rem.append(ch)
                      if self.showProgress:
                          self.progressDlg += 1
              # print "remove:", [ch.childPid for ch in rem]
              for ch in rem:
                  activeChilds.remove(ch)
                  while True:
                      try:
                          pid, exitcode = os.waitpid(ch.childPid, 0)
                          self.exitCodes.append(exitcode)
                          break
                      except OSError as ex:
                          if (
                              ex.errno == 4
                          ):  ## If we get this error, just try again
                              continue
                              # print "Ignored system call interruption"
                          else:
                              raise
  
                  # print [ch.childPid for ch in activeChilds]
  
              if self.showProgress and self.progressDlg.wasCanceled():
                  for ch in activeChilds:
                      ch.kill()
                  raise CanceledError()
  
              ## adjust polling interval--prefer to get exactly 1 event per poll cycle.
              if waitingChildren > 1:
                  pollInterval *= 0.7
              elif waitingChildren == 0:
                  pollInterval /= 0.7
              pollInterval = max(
                  min(pollInterval, 0.5), 0.0005
              )  ## but keep it within reasonable limits
  
              time.sleep(pollInterval)
      finally:
          if self.showProgress:
              self.progressDlg.__exit__(None, None, None)
          for ch in self.childs:
              ch.join()
      if len(self.exitCodes) < len(self.childs):
          raise Exception(
              "Parallelizer started %d processes but only received exit codes from %d."
              % (len(self.childs), len(self.exitCodes))
          )
      for code in self.exitCodes:
          if code != 0:
              raise Exception(
                  "Error occurred in parallel-executed subprocess (console output may have more information)."
              )
      return []
  
imports: import multiprocessing
  import os
  import re
  import sys
  import time
  from .processes import ForkedProcess
  from .remoteproxy import ClosedError
label_desc: Use image node_id 5 for calling the Parallelize obj's underlying member method code with example usage: obj.runParallel() and returns: list, Tasker