code: def run(self):
      # This is the main loop of the process. OK, so the way this works is
      # kind of brittle and stupid, but I had to figure out how to use the
      # multiprocessing module, work around bugs, and address performance
      # issues, so there is at least some reasoning behind some of this
  
      # The "parent" task farms individual documents out to the subtasks for
      # indexing. You could pickle the actual documents and put them in the
      # queue, but that is not very performant. Instead, we assume the tasks
      # share a filesystem and use that to pass the information around. The
      # parent task writes a certain number of documents to a file, then puts
      # the filename on the "job queue". A subtask gets the filename off the
      # queue and reads through the file processing the documents.
  
      jobqueue = self.jobqueue
      resultqueue = self.resultqueue
      multisegment = self.multisegment
  
      # Open a placeholder object representing the index
      ix = self.storage.open_index(self.indexname)
      # Open a writer for the index. The _lk=False parameter means to not try
      # to lock the index (the parent object that started me takes care of
      # locking the index)
      writer = self.writer = SegmentWriter(ix, _lk=False, **self.kwargs)
  
      # If the parent task calls cancel() on me, it will set self.running to
      # False, so I'll notice the next time through the loop
      while self.running:
          # Take an object off the job queue
          jobinfo = jobqueue.get()
          # If the object is None, it means the parent task wants me to
          # finish up
          if jobinfo is None:
              break
          # The object from the queue is a tuple of (filename,
          # number_of_docs_in_file). Pass those two pieces of information as
          # arguments to _process_file().
          self._process_file(*jobinfo)
          # jobqueue.task_done()
  
      if not self.running:
          # I was cancelled, so I'll cancel my underlying writer
          writer.cancel()
      else:
          if multisegment:
              # Actually finish the segment and return it with no run
              runname = None
              fieldnames = writer.pool.fieldnames
              segment = writer._finalize_segment()
          else:
              # Merge all runs in the writer's pool into one run, close the
              # segment, and return the run name and the segment
              k = self.kwargs.get("k", 64)
              runname, fieldnames, segment = finish_subsegment(
                  writer, k
              )
  
          # Put the results (the run filename and the segment object) on the
          # result queue
          resultqueue.put((runname, fieldnames, segment), timeout=5)
  
imports: from __future__ import with_statement
  from multiprocessing import Process, Queue, cpu_count
  from whoosh.compat import queue, xrange, pickle
  from whoosh.codec import base
  from whoosh.writing import SegmentWriter
  from whoosh.externalsort import imerge
  from whoosh.util import random_name
label_desc: Use image node_id 2 for calling the SubWriterTask obj's underlying member method code with example usage: obj.run() without return types