title: multiprocessing.Pool Scaling
body: <p>I am wondering why my CPU load is so low even though I do not get a high processing rate:</p>
  
  <pre><code>import time
  from multiprocessing import Pool
  import numpy as np
  from skimage.transform import AffineTransform, SimilarityTransform, warp
  
  center_shift = 256 / 2
  tf_center = SimilarityTransform(translation=-center_shift)
  tf_uncenter = SimilarityTransform(translation=center_shift)
  
  
  def sample_gen_random_i():
      for i in range(10000000000000):
          x = np.random.rand(256, 256, 4)
          y = [0]
  
          yield x, y
  
  
  def augment(sample):
      x, y = sample
      rotation = 2 * np.pi * np.random.random_sample()
      translation = 5 * np.random.random_sample(), 5 * np.random.random_sample()
      scale_factor = np.random.random_sample() * 0.2 + 0.9
      scale = scale_factor, scale_factor
  
      tf_augment = AffineTransform(scale=scale, rotation=rotation, translation=translation)
      tf = tf_center + tf_augment + tf_uncenter
  
      warped_x = warp(x, tf)
  
      return warped_x, y
  
  
  def augment_parallel_sample_gen(samples):
      p = Pool(4)
  
      for sample in p.imap_unordered(augment, samples, chunksize=10):
          yield sample
  
      p.close()
      p.join()
  
  
  def augment_sample_gen(samples):
      for sample in samples:
          yield augment(sample)
  
  
  
  # This is slow and the single cpu core has 100% load
  print('Single Thread --&gt; Slow')
  samples = sample_gen_random_i()
  augmented = augment_sample_gen(samples)
  
  start = time.time()
  for i, sample in enumerate(augmented):
      print(str(i) + '|' + str(i / (time.time() - start))[:6] + ' samples / second', end='\r')
      if i &gt;= 2000:
          print(str(i) + '|' + str(i / (time.time() - start))[:6] + ' samples / second')
          break
  
  # This is slow and there is only light load on the cpu cores
  print('Multithreaded --&gt; Slow')
  samples = sample_gen_random_i()
  augmented = augment_parallel_sample_gen(samples)
  
  start = time.time()
  for i, sample in enumerate(augmented):
      print(str(i) + '|' + str(i / (time.time() - start))[:6] + ' samples / second', end='\r')
      if i &gt;= 2000:
          print(str(i) + '|' + str(i / (time.time() - start))[:6] + ' samples / second')
          break
  </code></pre>
  
  <p>I am using multiprocessing.Pool's imap, but I think there is some overhead. I can reach about 500 samples/s when using no augmentation and no multiprocessing, 150 with augmentation no multiprocessing and like 170 with augmentation and multiprocessing so I suspect there must be something wrong with my approach.
  The code should be executable and self explanatory! :)</p>