webworker-threads
Advanced tools
Comparing version 0.4.0 to 0.4.1
@@ -0,1 +1,9 @@ | ||
## 0.4.1 | ||
### Global Worker API | ||
* Add `importScripts` for loading on-disk files. | ||
* Add `console.log` and `console.error` from thread.js. | ||
## 0.4.0 | ||
@@ -2,0 +10,0 @@ |
{ | ||
"name": "webworker-threads", | ||
"version": "0.4.0", | ||
"version": "0.4.1", | ||
"main": "build/Release/WebWorkerThreads.node", | ||
"description": "Lightweight Web Worker API implementation with POSIX threads", | ||
"description": "Lightweight Web Worker API implementation with native threads", | ||
"keywords": [ | ||
@@ -36,3 +36,3 @@ "threads", | ||
"scripts": { | ||
"js": "env PATH=./node_modules/.bin:\"$PATH\" lsc -cj package.ls;\ngcc deps/minifier/src/minify.c -o deps/minifier/bin/minify;\nenv PATH=./node_modules/.bin:\"$PATH\" lsc -cbp src/load.ls > src/load.js;\n./deps/minifier/bin/minify kLoad_js < src/load.js > src/load.js.c;\nenv PATH=./node_modules/.bin:\"$PATH\" lsc -cbp src/worker.ls > src/worker.js;\n./deps/minifier/bin/minify kWorker_js < src/worker.js > src/worker.js.c;\nenv PATH=./node_modules/.bin:\"$PATH\" lsc -cbp src/events.ls > src/events.js;\n./deps/minifier/bin/minify kEvents_js < src/events.js > src/events.js.c;\nenv PATH=./node_modules/.bin:\"$PATH\" lsc -cbp src/thread_nextTick.ls > src/thread_nextTick.js;\n./deps/minifier/bin/minify kThread_nextTick_js 1 < src/thread_nextTick.js > src/thread_nextTick.js.c;\nenv PATH=./node_modules/.bin:\"$PATH\" lsc -cbp src/createPool.ls > src/createPool.js;\n./deps/minifier/bin/minify kCreatePool_js < src/createPool.js > src/createPool.js.c;" | ||
"js": "env PATH=./node_modules/.bin:\"$PATH\" lsc -cj package.ls;\ngcc deps/minifier/src/minify.c -o deps/minifier/bin/minify;\nenv PATH=./node_modules/.bin:\"$PATH\" lsc -cbp src/worker.ls > src/worker.js;\n./deps/minifier/bin/minify kWorker_js < src/worker.js > src/worker.js.c;\nenv PATH=./node_modules/.bin:\"$PATH\" lsc -cbp src/events.ls > src/events.js;\n./deps/minifier/bin/minify kEvents_js < src/events.js > src/events.js.c;\nenv PATH=./node_modules/.bin:\"$PATH\" lsc -cbp src/createPool.ls > src/createPool.js;\n./deps/minifier/bin/minify kCreatePool_js < src/createPool.js > src/createPool.js.c;\nenv PATH=./node_modules/.bin:\"$PATH\" lsc -cbp src/thread_nextTick.ls > src/thread_nextTick.js;\n./deps/minifier/bin/minify kThread_nextTick_js 1 < src/thread_nextTick.js > src/thread_nextTick.js.c;\nenv PATH=./node_modules/.bin:\"$PATH\" lsc -cbp src/load.ls > src/load.js;\n./deps/minifier/bin/minify kLoad_js 1 1 < src/load.js > src/load.js.c;" | ||
}, | ||
@@ -39,0 +39,0 @@ "devDependencies": { |
333
README.md
@@ -51,7 +51,166 @@ # WebWorker Threads | ||
do spin = -> | ||
process.stdout.write '.' | ||
process.nextTick spin | ||
do spin = -> process.nextTick spin | ||
``` | ||
## Introduction | ||
After the initialization phase of a Node program, whose purpose is to setup listeners and callbacks to be executed in response to events, the next phase, the proper execution of the program, is orchestrated by the event loop whose duty is to [juggle events, listeners and callbacks quickly and without any hiccups nor interruptions that would ruin its performance](http://youtube.com/v/D0uA_NOb0PE?autoplay=1) | ||
Both the event loop and said listeners and callbacks run sequentially in a single thread of execution, Node's main thread. If any of them ever blocks, nothing else will happen for the duration of the block: no more events will be handled, no more callbacks nor listeners nor timeouts nor nextTick()ed functions will have the chance to run and do their job, because they won't be called by the blocked event loop, and the program will turn sluggish at best, or appear to be frozen and dead at worst. | ||
### What is WebWorker-Threads | ||
`webworker-threads` provides an asynchronous API for CPU-bound tasks that's missing in Node.js: | ||
``` javascript | ||
var Worker = require('webworker-threads').Worker; | ||
require('http').createServer(function (req,res) { | ||
var fibo = new Worker(function() { | ||
function fibo (n) { | ||
return n > 1 ? fibo(n - 1) + fibo(n - 2) : 1; | ||
} | ||
self.onmessage = function (event) { | ||
self.postMessage(fibo(event.data)); | ||
} | ||
}); | ||
fibo.onmessage = function (event) { | ||
res.end('fib(40) = ' + event.data); | ||
}; | ||
fibo.postMessage(40); | ||
}).listen(port); | ||
``` | ||
And it won't block the event loop because for each request, the `fibo` worker will run in parallel in a separate background thread. | ||
## API | ||
### Module API | ||
``` javascript | ||
var Threads= require('webworker-threads'); | ||
``` | ||
##### .Worker | ||
`new Threads.Worker( [ file | function ] )` -> Worker object | ||
##### .create() | ||
`Threads.create( /* no arguments */ )` -> thread object | ||
##### .createPool( numThreads ) | ||
`Threads.createPool( numberOfThreads )` -> threadPool object | ||
*** | ||
### Web Worker API | ||
``` javascript | ||
var worker= new Threads.Worker('worker.js'); | ||
var worker= new Threads.Worker(function(){ ... }); | ||
var worker= new Threads.Worker(); | ||
``` | ||
##### .postMessage( data ) | ||
`worker.postMessage({ x: 1, y: 2 })` -> sends a data structure into the worker. The worker can reive it using the `onmessage` handler. | ||
##### .onmessage | ||
`worker.onmessage = function (event) { console.log(event.data) };` -> receives data from the worker's `.postMessage` calls. | ||
##### .terminate() | ||
`worker.terminate()` -> terminates the worker thread. | ||
##### .addEventListener( type, cb ) | ||
`worker.addEventListener('message', callback)` is equivalent to setting `worker.onmesssage = callback`. | ||
##### .dispatchEvent( event ) | ||
Currently unimplemented. | ||
##### .removeEventListener( type ) | ||
Currently unimplemented. | ||
##### .thread | ||
Returns the underlying `thread` object; see the next section for details. | ||
Note that this attribute is implementation-specific, and not part of W3C Web Worker API. | ||
*** | ||
### Thread API | ||
``` javascript | ||
var thread= Threads.create(); | ||
``` | ||
##### .id | ||
`thread.id` -> a sequential thread serial number | ||
##### .load( absolutePath [, cb] ) | ||
`thread.load( absolutePath [, cb] )` -> reads the file at `absolutePath` and `thread.eval(fileContents, cb)`. | ||
##### .eval( program [, cb]) | ||
`thread.eval( program [, cb])` -> converts `program.toString()` and eval()s it in the thread's global context, and (if provided) returns the completion value to `cb(err, completionValue)`. | ||
##### .on( eventType, listener ) | ||
`thread.on( eventType, listener )` -> registers the listener `listener(data)` for any events of `eventType` that the thread `thread` may emit. | ||
##### .once( eventType, listener ) | ||
`thread.once( eventType, listener )` -> like `thread.on()`, but the listener will only be called once. | ||
##### .removeAllListeners( [eventType] ) | ||
`thread.removeAllListeners( [eventType] )` -> deletes all listeners for all eventTypes. If `eventType` is provided, deletes all listeners only for the event type `eventType`. | ||
##### .emit( eventType, eventData [, eventData ... ] ) | ||
`thread.emit( eventType, eventData [, eventData ... ] )` -> emit an event of `eventType` with `eventData` inside the thread `thread`. All its arguments are .toString()ed. | ||
##### .destroy( /* no arguments */ ) | ||
`thread.destroy( /* no arguments */ )` -> destroys the thread. | ||
*** | ||
### Thread pool API | ||
``` javascript | ||
threadPool= Threads.createPool( numberOfThreads ); | ||
``` | ||
##### .load( absolutePath [, cb] ) | ||
`threadPool.load( absolutePath [, cb] )` -> `thread.load( absolutePath [, cb] )` in all the pool's threads. | ||
##### .any.eval( program, cb ) | ||
`threadPool.any.eval( program, cb )` -> like `thread.eval()`, but in any of the pool's threads. | ||
##### .any.emit( eventType, eventData [, eventData ... ] ) | ||
`threadPool.any.emit( eventType, eventData [, eventData ... ] )` -> like `thread.emit()` but in any of the pool's threads. | ||
##### .all.eval( program, cb ) | ||
`threadPool.all.eval( program, cb )` -> like `thread.eval()`, but in all the pool's threads. | ||
##### .all.emit( eventType, eventData [, eventData ... ] ) | ||
`threadPool.all.emit( eventType, eventData [, eventData ... ] )` -> like `thread.emit()` but in all the pool's threads. | ||
##### .on( eventType, listener ) | ||
`threadPool.on( eventType, listener )` -> like `thread.on()`, registers listeners for events from any of the threads in the pool. | ||
##### .totalThreads() | ||
`threadPool.totalThreads()` -> returns the number of threads in this pool: as supplied in `.createPool( number )` | ||
##### .idleThreads() | ||
`threadPool.idleThreads()` -> returns the number of threads in this pool that are currently idle (sleeping) | ||
##### .pendingJobs() | ||
`threadPool.pendingJobs()` -> returns the number of jobs pending. | ||
##### .destroy( [ rudely ] ) | ||
`threadPool.destroy( [ rudely ] )` -> waits until `pendingJobs()` is zero and then destroys the pool. If `rudely` is truthy, then it doesn't wait for `pendingJobs === 0`. | ||
*** | ||
### Global Web Worker API | ||
Inside every Worker instance from webworker-threads, there's a global `self` object with these properties: | ||
##### .postMessage( data ) | ||
`self.postMessage({ x: 1, y: 2 })` -> sends a data structure back to the main thread. | ||
##### .onmessage | ||
`self.onmessage = function (event) { ... };` -> receives data from the main thread's `.postMessage` calls. | ||
##### .close() | ||
`self.close()` -> stops the current thread. | ||
##### .addEventListener( type, cb ) | ||
`self.addEventListener('message', callback)` is equivalent to setting `self.onmesssage = callback`. | ||
##### .dispatchEvent( event ) | ||
`self.dispatchEvent({ type: 'message', data: data })` -> same as `self.postMessage(data)`. | ||
##### .removeEventListener( type ) | ||
Currently unimplemented. | ||
##### .importScripts( file [, file...] ) | ||
Loads one or more files from the disk and `eval` them in the worker instance scope. | ||
##### .thread | ||
Returns the underlying `thread` object; see the next section for details. | ||
Note that this attribute is implementation-specific, and not part of W3C Web Worker API. | ||
*** | ||
### Global thread API | ||
Inside every thread .create()d by webworker-threads, there's a global `thread` object with these properties: | ||
##### .id | ||
`thread.id` -> the serial number of this thread | ||
##### .on( eventType, listener ) | ||
`thread.on( eventType, listener )` -> just like `thread.on()` above. | ||
##### .once( eventType, listener ) | ||
`thread.once( eventType, listener )` -> just like `thread.once()` above. | ||
##### .emit( eventType, eventData [, eventData ... ] ) | ||
`thread.emit( eventType, eventData [, eventData ... ] )` -> just like `thread.emit()` above. | ||
##### .removeAllListeners( [eventType] ) | ||
`thread.removeAllListeners( [eventType] )` -> just like `thread.removeAllListeners()` above. | ||
##### .nextTick( function ) | ||
`thread.nextTick( function )` -> like `process.nextTick()`, but twice as fast. | ||
*** | ||
### Global puts | ||
Inside every thread .create()d by webworker-threads, there's a global `puts`: | ||
##### puts(arg1 [, arg2 ...]) | ||
`puts(arg1 [, arg2 ...])` -> .toString()s and prints its arguments to stdout. | ||
----------- | ||
@@ -63,8 +222,4 @@ WIP WIP WIP | ||
## (not so) Quick Intro | ||
## Examples | ||
After the initialization phase of a Node program, whose purpose is to setup listeners and callbacks to be executed in response to events, the next phase, the proper execution of the program, is orchestrated by the event loop whose duty is to [juggle events, listeners and callbacks quickly and without any hiccups nor interruptions that would ruin its performance](http://youtube.com/v/D0uA_NOb0PE?autoplay=1) | ||
Both the event loop and said listeners and callbacks run sequentially in a single thread of execution, Node's main thread. If any of them ever blocks, nothing else will happen for the duration of the block: no more events will be handled, no more callbacks nor listeners nor timeouts nor nextTick()ed functions will have the chance to run and do their job, because they won't be called by the blocked event loop, and the program will turn sluggish at best, or appear to be frozen and dead at worst. | ||
**A.-** Here's a program that makes Node's event loop spin freely and as fast as possible: it simply prints a dot to the console in each turn: | ||
@@ -76,3 +231,2 @@ | ||
(function spinForever () { | ||
process.stdout.write("."); | ||
process.nextTick(spinForever); | ||
@@ -97,3 +251,2 @@ })(); | ||
(function spinForever () { | ||
process.stdout.write("."); | ||
process.nextTick(spinForever); | ||
@@ -122,3 +275,2 @@ })(); | ||
(function spinForever () { | ||
process.stdout.write("."); | ||
process.nextTick(spinForever); | ||
@@ -151,3 +303,2 @@ })(); | ||
(function spinForever () { | ||
process.stdout.write("."); | ||
process.nextTick(spinForever); | ||
@@ -175,3 +326,2 @@ })(); | ||
(function spinForever () { | ||
process.stdout.write("."); | ||
process.nextTick(spinForever); | ||
@@ -212,3 +362,2 @@ })(); | ||
(function spinForever () { | ||
process.stdout.write("."); | ||
process.nextTick(spinForever); | ||
@@ -250,3 +399,2 @@ })(); | ||
(function spinForever () { | ||
process.stdout.write("."); | ||
process.nextTick(spinForever); | ||
@@ -267,131 +415,2 @@ })(); | ||
## API | ||
### Module API | ||
``` javascript | ||
var Threads= require('webworker-threads'); | ||
``` | ||
##### .Worker | ||
`new Threads.Worker( [ file | function ] )` -> Worker object | ||
##### .create() | ||
`Threads.create( /* no arguments */ )` -> thread object | ||
##### .createPool( numThreads ) | ||
`Threads.createPool( numberOfThreads )` -> threadPool object | ||
*** | ||
### Web Worker API | ||
``` javascript | ||
var worker= new Threads.Worker('worker.js'); | ||
var worker= new Threads.Worker(function(){ ... }); | ||
var worker= new Threads.Worker(); | ||
``` | ||
##### .postMessage( data ) | ||
`worker.postMessage({ x: 1, y: 2 })` -> sends a data structure into the worker. The worker can reive it using the `onmessage` handler. | ||
##### .onmessage | ||
`worker.onmessage = function (event) { console.log(event.data) };` -> receives data from the worker's `.postMessage` calls. | ||
##### .terminate() | ||
`worker.terminate()` -> terminates the worker thread. | ||
##### .addEventListener( type, cb ) | ||
`worker.addEventListener('message', callback)` is equivalent to setting `worker.onmesssage = callback`. | ||
##### .dispatchEvent( event ) | ||
Currently unimplemented. | ||
##### .removeEventListener( type ) | ||
Currently unimplemented. | ||
##### .thread | ||
Returns the underlying `thread` object; see the next section for details. | ||
Note that this attribute is implementation-specific, and not part of W3C Web Worker API. | ||
*** | ||
### Thread API | ||
``` javascript | ||
var thread= Threads.create(); | ||
``` | ||
##### .id | ||
`thread.id` -> a sequential thread serial number | ||
##### .load( absolutePath [, cb] ) | ||
`thread.load( absolutePath [, cb] )` -> reads the file at `absolutePath` and `thread.eval(fileContents, cb)`. | ||
##### .eval( program [, cb]) | ||
`thread.eval( program [, cb])` -> converts `program.toString()` and eval()s it in the thread's global context, and (if provided) returns the completion value to `cb(err, completionValue)`. | ||
##### .on( eventType, listener ) | ||
`thread.on( eventType, listener )` -> registers the listener `listener(data)` for any events of `eventType` that the thread `thread` may emit. | ||
##### .once( eventType, listener ) | ||
`thread.once( eventType, listener )` -> like `thread.on()`, but the listener will only be called once. | ||
##### .removeAllListeners( [eventType] ) | ||
`thread.removeAllListeners( [eventType] )` -> deletes all listeners for all eventTypes. If `eventType` is provided, deletes all listeners only for the event type `eventType`. | ||
##### .emit( eventType, eventData [, eventData ... ] ) | ||
`thread.emit( eventType, eventData [, eventData ... ] )` -> emit an event of `eventType` with `eventData` inside the thread `thread`. All its arguments are .toString()ed. | ||
##### .destroy( /* no arguments */ ) | ||
`thread.destroy( /* no arguments */ )` -> destroys the thread. | ||
*** | ||
### Thread pool API | ||
``` javascript | ||
threadPool= Threads.createPool( numberOfThreads ); | ||
``` | ||
##### .load( absolutePath [, cb] ) | ||
`threadPool.load( absolutePath [, cb] )` -> `thread.load( absolutePath [, cb] )` in all the pool's threads. | ||
##### .any.eval( program, cb ) | ||
`threadPool.any.eval( program, cb )` -> like `thread.eval()`, but in any of the pool's threads. | ||
##### .any.emit( eventType, eventData [, eventData ... ] ) | ||
`threadPool.any.emit( eventType, eventData [, eventData ... ] )` -> like `thread.emit()` but in any of the pool's threads. | ||
##### .all.eval( program, cb ) | ||
`threadPool.all.eval( program, cb )` -> like `thread.eval()`, but in all the pool's threads. | ||
##### .all.emit( eventType, eventData [, eventData ... ] ) | ||
`threadPool.all.emit( eventType, eventData [, eventData ... ] )` -> like `thread.emit()` but in all the pool's threads. | ||
##### .on( eventType, listener ) | ||
`threadPool.on( eventType, listener )` -> like `thread.on()`, registers listeners for events from any of the threads in the pool. | ||
##### .totalThreads() | ||
`threadPool.totalThreads()` -> returns the number of threads in this pool: as supplied in `.createPool( number )` | ||
##### .idleThreads() | ||
`threadPool.idleThreads()` -> returns the number of threads in this pool that are currently idle (sleeping) | ||
##### .pendingJobs() | ||
`threadPool.pendingJobs()` -> returns the number of jobs pending. | ||
##### .destroy( [ rudely ] ) | ||
`threadPool.destroy( [ rudely ] )` -> waits until `pendingJobs()` is zero and then destroys the pool. If `rudely` is truthy, then it doesn't wait for `pendingJobs === 0`. | ||
*** | ||
### Global Web Worker API | ||
Inside every Worker instance from webworker-threads, there's a global `self` object with these properties: | ||
##### .postMessage( data ) | ||
`self.postMessage({ x: 1, y: 2 })` -> sends a data structure back to the main thread. | ||
##### .onmessage | ||
`self.onmessage = function (event) { ... };` -> receives data from the main thread's `.postMessage` calls. | ||
##### .close() | ||
`self.close()` -> stops the current thread. | ||
##### .addEventListener( type, cb ) | ||
`self.addEventListener('message', callback)` is equivalent to setting `self.onmesssage = callback`. | ||
##### .dispatchEvent( event ) | ||
`self.dispatchEvent({ type: 'message', data: data })` -> same as `self.postMessage(data)`. | ||
##### .removeEventListener( type ) | ||
Currently unimplemented. | ||
##### .thread | ||
Returns the underlying `thread` object; see the next section for details. | ||
Note that this attribute is implementation-specific, and not part of W3C Web Worker API. | ||
*** | ||
### Global thread API | ||
Inside every thread .create()d by webworker-threads, there's a global `thread` object with these properties: | ||
##### .id | ||
`thread.id` -> the serial number of this thread | ||
##### .on( eventType, listener ) | ||
`thread.on( eventType, listener )` -> just like `thread.on()` above. | ||
##### .once( eventType, listener ) | ||
`thread.once( eventType, listener )` -> just like `thread.once()` above. | ||
##### .emit( eventType, eventData [, eventData ... ] ) | ||
`thread.emit( eventType, eventData [, eventData ... ] )` -> just like `thread.emit()` above. | ||
##### .removeAllListeners( [eventType] ) | ||
`thread.removeAllListeners( [eventType] )` -> just like `thread.removeAllListeners()` above. | ||
##### .nextTick( function ) | ||
`thread.nextTick( function )` -> like `process.nextTick()`, but twice as fast. | ||
*** | ||
### Global puts | ||
Inside every thread .create()d by webworker-threads, there's a global `puts`: | ||
##### puts(arg1 [, arg2 ...]) | ||
`puts(arg1 [, arg2 ...])` -> .toString()s and prints its arguments to stdout. | ||
## Rationale | ||
@@ -430,27 +449,2 @@ | ||
### What is Threads A GoGo for Node.js | ||
`webworker-threads` provides the asynchronous API for CPU-bound tasks that's missing in Node.js. Both in continuation passing style (callbacks), and in event emitter style (event listeners). | ||
The same API Node uses to delegate a longish I/O task to a background (libeio) thread: | ||
`asyncIOTask(what, cb);` | ||
`webworker-threads` uses to delegate a longish CPU task to a background (JavaScript) thread: | ||
`thread.eval(program, cb);` | ||
So with `webworker-threads` you can write: | ||
``` javascript | ||
http.createServer(function (req,res) { | ||
thread.eval('fibonacci(40)', function cb (err, data) { | ||
res.end(data); | ||
}); | ||
}).listen(port); | ||
``` | ||
And it won't block the event loop because the `fibonacci(40)` will run in parallel in a separate background thread. | ||
### Why Threads | ||
@@ -468,3 +462,2 @@ | ||
### Why not multiple processes. | ||
@@ -471,0 +464,0 @@ |
@@ -1,3 +0,14 @@ | ||
function load(p, cb){ | ||
return this.eval(require('fs').readFileSync(p, 'utf8'), cb); | ||
function addEventListener(event, cb){ | ||
return this.thread.on(event, cb); | ||
} | ||
function close(){ | ||
return this.thread.emit('close'); | ||
} | ||
function importScripts(){ | ||
var i$, len$, p, results$ = []; | ||
for (i$ = 0, len$ = arguments.length; i$ < len$; ++i$) { | ||
p = arguments[i$]; | ||
results$.push(self.eval(native_fs_.readFileSync(p, 'utf8'))); | ||
} | ||
return results$; | ||
} |
@@ -28,8 +28,2 @@ function ThreadNextTick(){ | ||
thread.nextTick = nextTick; | ||
self.addEventListener = function(event, cb){ | ||
return this.thread.on(event, cb); | ||
}; | ||
self.close = function(){ | ||
return this.thread.emit('close'); | ||
}; | ||
Object.defineProperty(self, 'onmessage', { | ||
@@ -36,0 +30,0 @@ set: function(cb){ |
* Worker API | ||
* `importScripts` | ||
Probably just forward to `require`. | ||
* `setTimeout` / `clearTimeout` / `setInterval` / `clearInterval` | ||
@@ -5,0 +3,0 @@ Forwarding to the default implementation. |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
239708
102
1751
0
456