      def threaded_io(self, task, io_args=None):
          """ Perform I/O task in a background thread """
          logger.debug("Threading task: (Task: '%s')", task)
          io_args = tuple() if io_args is None else (io_args, )
          if task == "load":
              func = self.load_images
          elif task == "save":
              func = self.save_faces
          elif task == "reload":
              func = self.reload_images
          io_thread = MultiThread(func, *io_args, thread_count=1)
          io_thread.start()
          self.threads.append(io_thread)
  
      def load_images(self):
 
</s> remove     def threaded_io(self, task, io_args=None):
        """ Perform I/O task in a background thread """
 </s> add     def _threaded_redirector(self, task, io_args=None):
        """ Redirect image input/output tasks to relevant queues in background thread

        Parameters
        ----------
        task: str
            The name of the task to be put into a background thread
        io_args: tuple, optional
            Any arguments that need to be provided to the background function
        """ </s> remove         self.threads.append(io_thread)
 </s> add         self._threads.append(io_thread)

    def _load(self):
        """ Load the images </s> remove         self.alignments.save()
        Utils.finalize(self.images.images_found // self.skip_num,
                       self.alignments.faces_count,
                       self.verify_output)
 </s> add         self._alignments.save()
        Utils.finalize(self._images.process_count + self._existing_count,
                       self._alignments.faces_count,
                       self._verify_output) </s> remove     def load_images(self):
        """ Load the images """
 </s> add         Loads images from :class:`lib.image.ImagesLoader`, formats them into a dict compatible
        with :class:`plugins.extract.Pipeline.Extractor` and passes them into the extraction queue.
        """ </s> remove         io_args = (self._queue) if io_args is None else (self._queue, *io_args)
        retval = MultiThread(getattr(self, "_{}".format(self._task)), *io_args, thread_count=1)
        logger.trace(retval)
        return retval
 </s> add         if self._is_video:
            self._count = int(count_frames(self.location, fast=fast_count))
            self._file_list = [self._dummy_video_framename(i + 1) for i in range(self.count)]
        else:
            if isinstance(self.location, (list, tuple)):
                self._file_list = self.location
            else:
                self._file_list = get_image_paths(self.location)
            self._count = len(self.file_list)
        func = getattr(self, "_{}".format(task))
      def threaded_io(self, task, io_args=None):
          """ Perform I/O task in a background thread """
          logger.debug("Threading task: (Task: '%s')", task)
          io_args = tuple() if io_args is None else (io_args, )
        func = getattr(self, "_{}".format(task))
        func = getattr(self, "_{}".format(task))
        func = getattr(self, "_{}".format(task))
        func = getattr(self, "_{}".format(task))
        func = getattr(self, "_{}".format(task))
        func = getattr(self, "_{}".format(task))
          io_thread = MultiThread(func, *io_args, thread_count=1)
          io_thread.start()
          self.threads.append(io_thread)
  
      def load_images(self):
keep keep keep keep replace replace replace replace replace replace keep keep keep keep keep
 scripts.extract - code optimizations

Limit queue sizes to reduce RAM usage
Rename lib.image.BackgroundIO to ImageIO
Create separate ImagesLoader and ImagesSaver classes
Load/Save images from centralized lib.image.ImageIO
scripts.extract documentation 
scripts/extract.py