# spacepy.toolbox.thread_job

spacepy.toolbox.thread_job(job_size, thread_count, target, *args, **kwargs)

  Split a job into subjobs and run a thread for each

  Each thread spawned will call L{target} to handle a slice of the job.

  This is only useful if a job:

    1. Can be split into completely independent subjobs

    2. Relies heavily on code that does not use the Python GIL, e.g. numpy or ctypes code

    3. Does not return a value. Either pass in a list/array to hold the result, or see L{thread_map}

  Parameters
    job_size int

      Total size of the job. Often this is an array size.

    thread_count int
      Number of threads to spawn. If =0 or None, will

        spawn as many threads as there are cores available on the system. (Each hyperthreading core counts as 2.) Generally this is the Right Thing to do. If NEGATIVE, will spawn abs(thread_count) threads, but will run them sequentially rather than in parallel; useful for debugging.

    target callable
      Python callable (generally a function, may also be an

        imported ctypes function) to run in each thread. The last two positional arguments passed in will be a “start” and a “subjob size,” respectively; frequently this will be the start index and the number of elements to process in an array.

    args sequence
      Arguments to pass to L{target}. If L{target} is an instance

        method, self must be explicitly passed in. start and subjob_size will be appended.

    kwargs dict

      keyword arguments to pass to L{target}.

  Examples

  squaring 100 million numbers:

      >>> import numpy
      >>> import spacepy.toolbox as tb
      >>> numpy.random.seed(8675301)
      >>> a = numpy.random.randint(0, 100, [100000000])
      >>> b = numpy.empty([100000000], dtype='int64')
      >>> def targ(in_array, out_array, start, count):              out_array[start:start + count] = in_array[start:start + count] ** 2
      >>> tb.thread_job(len(a), 0, targ, a, b)
      >>> print(b[0:5])
      [2704 7225  196 1521   36]

  This example:

    - Defines a target function, which will be called for each thread. It is usually necessary to define a simple “wrapper” function like this to provide the correct call signature.

    - The target function receives inputs C{in_array} and C{out_array}, which are not touched directly by C{thread_job} but are passed through in the call. In this case, C{a} gets passed as C{in_array} and C{b} as C{out_array}

    - The target function also receives the start and number of elements it needs to process. For each thread where the target is called, these numbers are different.