Common 'Thread' behavior for Browsers (using Web Workers) or Node (using Child Process).
Common "Thread" behavior for Browsers (using Web Workers) or Node (using Child Process).
- Create a Thread or a ThreadPool of multiple threads.
- Install a function to the Thread/ThreadPool without having to predefine it in the slave/child loading file.
- Once installed installed functions can be repeatedly called without the performance penalty of installing the function each time.
- In a ThreadPool with more than one thread Install is done on all Threads, and execution is done on a single thread, (whichever is the next thread in the pool.)
- Uses a common module file for both the master and slave/child processes, thus taking advantage of browser caching.
- Provides the ability to execute certain functions (called "Selfies") back on the master from a slave/child (one way). For example, Web Workers do not have a
consoleoption, but with a
console.logselfie, the slave/child can do
console.logback on the server.
- "Threadify" a function so all calls of that function are automatically run on the Thread/ThreadPool.
- Single Execution of a function without the need to install for one-off behavior. (Incurrs the perfromance penalty of having to install though).
Threadful attempts to shave millis off the performance costs whereever possible. By having an
Install mechanism, Threadful allows the developer to minimize the performance penalty assocated with dynamically executing functions in a Thread.
On average we have seen the following performance... Your own results may vary.
Require Threadful (on Node) ................... 4 ms.Creating a Thread ............................. 8 ms.Install a Function ............................ 74 ms.Execute an Installed Function ................. 3 ms.Execute a not previously installed Function ... 78 ms.Threadify a Function .......................... 74 ms.Execute a Threadified Function ................ 3 ms.
Given these numbers and other test, one should carefully weigh whether executing in a thread is necessary or not. Thread code that takes a long time to perform, generally does better in a thread than that which is quickly but often performed. Large calculations perform much better than small things, quality over quantity.
In our example code, we wrote a very simplistic prime number test and then let it run for 10 seconds. We compared running in the main thread to distributing the work across a large number of threads. Here are the results we saw...
Thread Number of Small Primes Large PrimesModel Threads Found in 10s Found in 10sUsed (incl Main) >0 >10000000-------------- ----------- --------------- ---------------Single Thread 1+0 23967 / --- 340 / ----Multi Thread 1+1 11787 / 49% 314 / 92%Multi Thread 1+2 16556 / 69% 635 / 187%Multi Thread 1+4 20080 / 84% 1065 / 313%Multi Thread 1+6 19238 / 80% 1230 / 362%Multi Thread 1+8 17585 / 73% 1311 / 386%Multi Thread 1+12 14683 / 61% 1305 / 384%Multi Thread 1+16 12556 / 52% 1293 / 380%Multi Thread 1+24 8585 / 36% 1263 / 371%Multi Thread 1+48 3717 / 16% 1122 / 330%(Test run on a 4 core intel chip with HyperThreading)
Our results indicate that when working with small primes, using threads was detrimental because the small primes are so quickly calculated individually. However, when we switched to large primes we saw immediate benefit from using thread because large prime calculations take more time individually. Our results also illustrate the diminishing return point of exceeding the number of "cores" available.
You can get Threadful from npm using the command
npm install Threadful
Once obtained you can use Threadful in your own code thus
Node.js - via require
// Require Threadfulvar Threadful = require"Threadful";
Browser - Insert a script tag
<!-- Install Threadful -->
Please Note: Installing Threadful in a browser create the global object Threadful.
Threadful uses callbacks to notify when things are complete. All callbacks have the form
callback(error,result). If error is not null, some error occured during execution. Otherwise a valid result will be populated, if any was sent back.
You can create a pool of threads just as easily using the
new Threadful.ThreadPool(options) constructor. You just need to specify the number threads you wish in the pool. Threads can added or removed after the pool has been created with
Threadful.ThreadPool returns a new ThreadPool object. See below for details.
var threadpool =threads: 4timeout: 500;
You can create a single Thread using the
new Threadful.Thread() constructor.. Note that creating a single thread is really jsut a wrapper for creating a thread pool with 1 thread and a timeout of500ms.
Threadful.Thread returns a new ThreadPool object. See below for details.
// Create a new Threadvar thread = ;
Threadify is a process that when given a function will create a Thread, install the function into the thread, and return a new function. When the new function is executed the actual execution is passed off to the original function in the thread. It essentially wraps a function in a Thread execution. It is provided purely for quick and easy access but does have some limitations...
- Threadify functions are self contained Threads and not shared with other functions.
- Threadify functions cannot (at this time) be unwound from their Thread.
- Threadify functions do not expose thier underlying Thread (yet).
- Threadify functions cannot be closed (yet).
Instead of using Threadful.Threadify consider creating a new Thread and using the Thread.threadify() method there.
Threadful.Threadify returns a new function, which serves as the means to execute the original function but on the thread created. The function will take any number of parameters, but the last parameter should be a callback function to be notified of the result of execution.
// Define some functionvar ;// Create a Threadify version of that functionvar threaded = ThreadfulThreadifyf;// Execute the function f on a Thread.threaded123callback; // execute function f on the thread, return result in the callback.
Execute is a one time thread execution for a passed in function. It create a single use Thread, installs the function into it, and then executes the function immediately. Once execution is complete the Thread is closed and no longer usable. Threadful.Execute has some very consquental limitations, so use with care.
- It is single use.
- Each time you use Execute you pay the performance of creating a new thread, installing the function, and executing the function all at once.
- The created thread cannot be reused.
Instead of using Threadful.Execute consider creating a new Thread, installing the function to the Thread, and using Thread.execute() to run it.
Execute returns nothing.
// Define some functionvar ;// Execute that function on a Thread.ThreadfulExecutefarg1arg2arg3argEtccallback;
Closes all previously created ThreadPool objects including those created by Threadful.Threadify and Threadful.Execute. Once a ThreadPool is closed it cannot be reused.
Once a Thread or ThreadPool is instantiated with
new Thread() or
new ThreadPool(), you can perform the following operations on either.