A thread pool executes one or more functions asynchronously.

In multi-threaded mode, jobs run on background threads. In HTML5, this means using web workers, which impose additional restrictions (see below). In single-threaded mode, jobs run between frames on the main thread. To avoid blocking, these jobs should only do a small amount of work at a time.

In multi-threaded mode, the pool spins up new threads as jobs arrive (up to maxThreads). If too many jobs arrive at once, it places them in a queue to run when threads open up. If you run jobs frequently but not constantly, you can also set minThreads to keep a certain number of threads alive, avoiding the overhead of repeatedly spinning them up.

Sample usage:

var threadPool:ThreadPool = new ThreadPool();
threadPool.onComplete.add(onFileProcessed);

threadPool.maxThreads = 3;
for(url in urls)
{
	threadPool.run(processFile, url);
}

Guidelines to make your code work on all targets and configurations:

  • For thread safety and web worker compatibility, your work function should only return data through the WorkOutput object it receives.
  • For web worker compatibility, you should only send data to your work function via the State object. But since this can be any object, you can put an arbitrary amount of data there.
  • For web worker compatibility, your work function must be static, and you can't bind() any extra arguments.
  • For single-threaded performance, your function should only do a small amount of work at a time. Store progress in the State object so you can pick up where you left off. You don't have to worry about timing: just aim to take a small fraction of the frame's time, and ThreadPool will keep running the function until enough time passes.

Static variables

@:value(1 / 2)staticworkLoad:Float = 1 / 2

A rough estimate of how much of the app's time should be spent on single-threaded jobs, across all active ThreadPools. For instance, the default value of 1/2 means ThreadPools will attempt to use about half the app's available time every frame.

The accuracy of this estimate depends on how often your work functions return. If you find that a ThreadPool is taking longer than scheduled, try making the work function return more often.

Static methods

staticinlineisMainThread():Bool

Returns whether the caller called this function from the main thread.

Constructor

@:value({ mode : null, maxThreads : 1, minThreads : 0 })new(minThreads:Int = 0, maxThreads:Int = 1, ?mode:ThreadMode)

Call this only from the main thread.

Parameters:

minThreads

The number of threads that will be kept alive at all times, even if there's no work to do. The threads won't spin up immediately; only after enough calls to run().

maxThreads

The maximum number of threads that will run at once.

mode

The mode jobs will run in by default. Defaults to SINGLE_THREADED in HTML5 for backwards compatibility.

Variables

read onlyactiveJobs:Int

The number of jobs actively being executed.

@:value(0)read onlyactiveThreads:Int = 0

The number of jobs currently running on a background thread.

read onlycurrentThreads:Int

The number of background threads in this pool, including both active and idle threads. Does not include threads that are shutting down.

read onlyidleThreads:Int

The number of background threads in this pool that are currently idle, neither working on a job nor shutting down.

maxThreads:Int

Set this only from the main thread.

The maximum number of background threads this pool can have at once. If this value decreases, active jobs will still be allowed to finish.

minThreads:Int

Set this only from the main thread.

The number of background threads that will be kept alive at all times, even if there's no work to do. Setting this won't immediately spin up new threads; you must still call run() to get them started.

@:value(new Event<Dynamic>())read onlyonComplete:_Event_Dynamic_Void<Dynamic ‑> Void> = new Event<Dynamic>()

Dispatched on the main thread when doWork calls sendComplete(). Dispatched at most once per job.

@:value(new Event<Dynamic>())read onlyonError:_Event_Dynamic_Void<Dynamic ‑> Void> = new Event<Dynamic>()

Dispatched on the main thread when doWork calls sendError(). Dispatched at most once per job.

@:value(new Event<Dynamic>())read onlyonProgress:_Event_Dynamic_Void<Dynamic ‑> Void> = new Event<Dynamic>()

Dispatched on the main thread when doWork calls sendProgress(). May be dispatched any number of times per job.

@:value(new Event<State>())read onlyonRun:_Event_lime_system_State_Void<State ‑> Void> = new Event<State>()

Dispatched on the main thread when a new job begins. Dispatched exactly once per job.

@:value(new Event<Exception>())read onlyonUncaughtError:_Event_haxe_Exception_Void<Exception ‑> Void> = new Event<Exception>()

Dispatched on the main thread when doWork throws an error. Dispatched at most once per job.

If no listeners have been added, instead the error will be rethrown.

@:value(1)workPriority:Float = 1

How important this pool's single-threaded jobs are, relative to other pools. Pools will be allocated a share of the time per frame (see workLoad) based on their importance.

For instance, if all pools use the default priority of 1, they will all run for an approximately equal amount of time each frame. If one has a value of 2, it will run approximately twice as long as the others.

Methods

@:value({ error : null })cancel(?error:Dynamic):Void

Cancels all active and queued jobs.

Note: It isn't possible to terminate a job from the outside, so canceled jobs may continue to run for some time. However, any events they send will be ignored.

Parameters:

error

If not null, this error will be dispatched for each active or queued job.

cancelJob(jobID:Int):Bool

Cancels one active or queued job. Does not dispatch an error event.

Note: It isn't possible to terminate a job from the outside, so the job may continue to run for some time. However, any events it sends will be ignored.

Returns:

Whether a job was canceled.

@:value({ mode : null, state : null, doWork : null })run(?doWork:WorkFunction<(State, WorkOutput) ‑> Void>, ?state:Null<State>, ?mode:ThreadMode):Int

Runs the given function asynchronously, or queues it for later if no more threads are available.

Parameters:

doWork

The function to run. For best results, see the guidelines in the ThreadPool class overview. In brief: doWork should be static, only access its arguments, and return often.

state

An object to pass to doWork. Consider passing a mutable object so that doWork can save its progress.

mode

Which mode to run the job in. If omitted, the pool's default mode will be used.

Returns:

The job's unique ID.

Inherited Variables

Defined by WorkOutput

activeJob:Null<JobData>

The job that is currently running on this thread, or the job that triggered the ongoing event (onComplete, onProgress, etc.). Will be null in all other cases.

mode:ThreadMode

The mode jobs will run in by default. If threads aren't available, jobs will always run in SINGLE_THREADED mode.

@:value(new Tls())read onlyworkIterations:Tls<Int> = new Tls()

Available on Android, Linux, Mac, Windows, iOS

Thread-local storage. Tracks how many times doWork has been called for the current job, including (if applicable) the ongoing call.

In single-threaded mode, it only counts the number of calls this frame. The lower the number, the less accurate ThreadPool.workLoad becomes, but the higher the number, the more overhead there is. As a ballpark estimate, aim for 10-100 iterations.

Inherited Methods