Skip to content
Snippets Groups Projects
Commit aa5aa6b3 authored by Elisa Giglio's avatar Elisa Giglio
Browse files

rimosso file superflui 3

parent 4ee851ba
No related branches found
No related tags found
No related merge requests found
The MIT License (MIT)
Copyright (c) 2014 Keith Horwood
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Multithread
===========
In-browser multithreading made easy.
Run any business logic you like without interrupting the user experience.
Multithread is a simple wrapper that eliminates the hassle of dealing with Web Workers and
transferrable objects.
Run any code you'd like asynchronously, in its own thread, without interrupting the user experience.
Using Multithread
-----------------
Using Multithread is simple. Include multithread.js on any page you'd like using
```html
<script src="my/path/to/multithread.js"></script>
```
And instantiate it in any script tag using
```js
var num_threads = 2;
var MT = new Multithread(num_threads);
```
Multithread will provide the best results when ```num_threads``` matches the processor core count of the computer
you're using, but 2-4 threads should always be reasonably speedy.
Running a Thread Asynchronously
-------------------------------
The fun stuff! Run any code you want (in the form of a function) asynchronously, in a separate thread like so:
```js
MT.process(function, callback)(arg1, arg2, ..., argN);
```
Where ```function``` is of the form:
```js
function(arg1, arg2, ... argN) {
/* function body */
}
```
and ```callback``` is of the form:
```js
function(returnValue) {
/* do something with returnValue in main thread */
}
```
Note that ```.process()``` itself will return a function object that will not execute until explicitly
told to do so.
```js
var funcInADifferentThread = MT.process(
function(a, b) { return a + b; },
function(r) { console.log(r) }
);
// Nothing has happened,
//funcInADifferentThread has not executed yet...
funcInADifferentThread(1, 2);
console.log('Before or after?');
// We now see "Before or after?" logged in the console,
// and "3" (= 1 + 2) logged shortly thereafter...
// it was running asynchronously
```
Special Data Types
------------------
Multithread.js uses JSON serialization with ```.process()``` so you can deal with your threaded,
asynchronous functions like you'd deal with normal JavaScript functions.
However, optimized support is also provided for typed data, specifically ```Int32``` and ```Float64```
(being signed 32-bit integers and 64-bit floats, respectively).
You can access these using...
```js
// Only deal with 32-bit signed integers...
var threadedInt32Func = MT.processInt32(
function(int32_arg1, int32_arg2, ..., int32_argN) {
/* function body */
},
function(int32_returnValue1, int32_returnValue2, ..., int32_returnValueN) {
/* main thread callback */
}
);
// Only deal with 64-bit floats...
var threadedFloat64Func = MT.processFloat64(
function(float64_arg1, float64_arg2, ..., float64_argN) {
/* function body */
},
function(float64_returnValue1, float64_returnValue2, ..., float64_returnValueN) {
/* main thread callback */
}
);
```
You may notice that the threaded functions take an argument list of Int32 and Float64 data,
and the most common use case is more likely an array of data. In this case, feel free to use
Javascript's ```Function.prototype.apply(context, argArray)``` to send your array as an argument list.
```js
// Use Function.apply to send arguments as an array
threadedInt32Func.apply(null, [32, 64, 128, 256])
```
Note that threaded functions can not have their context set, so the first argument to ```.apply``` should
always be ```null```.
Additionally, a keen observer would detect that the ```callback``` format is also a little bit different. The return from a ```.processInt32``` or ```.processFloat64``` threaded function can be a single value or Array.
The arguments sent to ```callback``` are the values of a returned array, in order, or just a single argument
representing a single returned value. These values can be accessed via the magic ```arguments``` object,
but you may want built-in Array functionality, in which case you can convert this arguments object into
an array:
```js
// your callback
function callback() {
var argumentArray = [].slice.call(arguments);
/* do something with your argumentArray here */
}
```
That's it! ... Almost.
Scope Warning
-------------
Keep in mind that any threaded function is **completely scope unaware**, meaning something like:
```js
function scopeCheck() {
var scopeVar = 2;
MT.process(
function() { return scopeVar + 2; },
function(r) { console.log('Cool'); }
)();
}
scopeCheck();
```
Will throw ```ReferenceError: scopeVar is not defined```
However, **callbacks are scope aware** so you needn't be as careful with them.
Recursion
---------
You can accomplish recursion simply by naming your functions as you pass them to Multithread
```js
MT.process(
function Recurse(m, n) {
if(n>0) {
return Recurse(m + 1, n--);
} else {
return m;
}
},
function(r) {
console.log(r);
}
)(5, 2);
// This will increase m twice recursively and log "7"
```
Limitations
-----------
Be aware of the limitations of multithreading in JavaScript.
All variables passed to functions must be JSON-serializable, meaning only Arrays, Objects, and base types (Number, String, Boolean, null). Same with return variables. No custom objects or prototypes.
Objects and Arrays, as passed to any threaded function, will be deep-copied (passed by value, not reference).
Additionally, threaded functions do not have access to the DOM.
Thank You
---------
Thanks, and have fun! :)
Feedback is always appreciated. (Stars, forks, criticisms, you name it!)
You can follow me on twitter at http://twitter.com/keithwhor or visit my website at http://keithwhor.com/
!function() {
var URL = window.URL || window.webkitURL;
if(!URL) {
throw new Error('This browser does not support Blob URLs');
}
if(!window.Worker) {
throw new Error('This browser does not support Web Workers');
}
function Multithread(threads) {
this.threads = Math.max(2, threads | 0);
this._queue = [];
this._queueSize = 0;
this._activeThreads = 0;
this._debug = {
start: 0,
end: 0,
time: 0
};
}
Multithread.prototype._worker = {
JSON: function() {
var /**/name/**/ = (/**/func/**/);
self.addEventListener('message', function(e) {
var data = e.data;
var view = new DataView(data);
var len = data.byteLength;
var str = Array(len);
for(var i=0;i<len;i++) {
str[i] = String.fromCharCode(view.getUint8(i));
}
var args = JSON.parse(str.join(''));
var value = (/**/name/**/).apply(/**/name/**/, args);
try {
data = JSON.stringify(value);
} catch(e) {
throw new Error('Parallel function must return JSON serializable response');
}
len = typeof(data)==='undefined'?0:data.length;
var buffer = new ArrayBuffer(len);
view = new DataView(buffer);
for(i=0;i<len;i++) {
view.setUint8(i, data.charCodeAt(i) & 255);
}
self.postMessage(buffer, [buffer]);
self.close();
})
},
Int32: function() {
var /**/name/**/ = (/**/func/**/);
self.addEventListener('message', function(e) {
var data = e.data;
var view = new DataView(data);
var len = data.byteLength / 4;
var arr = Array(len);
for(var i=0;i<len;i++) {
arr[i] = view.getInt32(i*4);
}
var value = (/**/name/**/).apply(/**/name/**/, arr);
if(!(value instanceof Array)) { value = [value]; }
len = value.length;
var buffer = new ArrayBuffer(len * 4);
view = new DataView(buffer);
for(i=0;i<len;i++) {
view.setInt32(i*4, value[i]);
}
self.postMessage(buffer, [buffer]);
self.close();
})
},
Float64: function() {
var /**/name/**/ = (/**/func/**/);
self.addEventListener('message', function(e) {
var data = e.data;
var view = new DataView(data);
var len = data.byteLength / 8;
var arr = Array(len);
for(var i=0;i<len;i++) {
arr[i] = view.getFloat64(i*8);
}
var value = (/**/name/**/).apply(/**/name/**/, arr);
if(!(value instanceof Array)) { value = [value]; }
len = value.length;
var buffer = new ArrayBuffer(len * 8);
view = new DataView(buffer);
for(i=0;i<len;i++) {
view.setFloat64(i*8, value[i]);
}
self.postMessage(buffer, [buffer]);
self.close();
})
}
};
Multithread.prototype._encode = {
JSON: function(args) {
try {
var data = JSON.stringify(args);
} catch(e) {
throw new Error('Arguments provided to parallel function must be JSON serializable');
}
len = data.length;
var buffer = new ArrayBuffer(len);
var view = new DataView(buffer);
for(var i=0;i<len;i++) {
view.setUint8(i, data.charCodeAt(i) & 255);
}
return buffer;
},
Int32: function(args) {
len = args.length;
var buffer = new ArrayBuffer(len*4);
var view = new DataView(buffer);
for(var i=0;i<len;i++) {
view.setInt32(i*4, args[i]);
}
return buffer;
},
Float64: function(args) {
len = args.length;
var buffer = new ArrayBuffer(len*8);
var view = new DataView(buffer);
for(var i=0;i<len;i++) {
view.setFloat64(i*8, args[i]);
}
return buffer;
}
};
Multithread.prototype._decode = {
JSON: function(data) {
var view = new DataView(data);
var len = data.byteLength;
var str = Array(len);
for(var i=0;i<len;i++) {
str[i] = String.fromCharCode(view.getUint8(i));
}
if(!str.length) {
return;
} else {
return JSON.parse(str.join(''));
}
},
Int32: function(data) {
var view = new DataView(data);
var len = data.byteLength / 4;
var arr = Array(len);
for(var i=0;i<len;i++) {
arr[i] = view.getInt32(i*4);
}
return arr;
},
Float64: function(data) {
var view = new DataView(data);
var len = data.byteLength / 8;
var arr = Array(len);
for(var i=0;i<len;i++) {
arr[i] = view.getFloat64(i*8);
}
return arr;
},
};
Multithread.prototype._execute = function(resource, args, type, callback) {
if(!this._activeThreads) {
this._debug.start = (new Date).valueOf();
}
if(this._activeThreads < this.threads) {
this._activeThreads++;
var t = (new Date()).valueOf();
var worker = new Worker(resource);
var buffer = this._encode[type](args);
var decode = this._decode[type];
var self = this;
if(type==='JSON') {
var listener = function(e) {
callback.call(self, decode(e.data));
self.ready();
};
} else {
var listener = function(e) {
callback.apply(self, decode(e.data));
self.ready();
};
}
worker.addEventListener('message', listener);
worker.postMessage(buffer, [buffer]);
} else {
this._queueSize++;
this._queue.push([resource, args, type, callback]);
}
};
Multithread.prototype.ready = function() {
this._activeThreads--;
if(this._queueSize) {
this._execute.apply(this, this._queue.shift());
this._queueSize--;
} else if(!this._activeThreads) {
this._debug.end = (new Date).valueOf();
this._debug.time = this._debug.end - this._debug.start;
}
};
Multithread.prototype._prepare = function(fn, type) {
fn = fn;
var name = fn.name;
var fnStr = fn.toString();
if(!name) {
name = '$' + ((Math.random()*10)|0);
while (fnStr.indexOf(name) !== -1) {
name += ((Math.random()*10)|0);
}
}
var script = this._worker[type]
.toString()
.replace(/^.*?[\n\r]+/gi, '')
.replace(/\}[\s]*$/, '')
.replace(/\/\*\*\/name\/\*\*\//gi, name)
.replace(/\/\*\*\/func\/\*\*\//gi, fnStr);
var resource = URL.createObjectURL(new Blob([script], {type: 'text/javascript'}));
return resource;
};
Multithread.prototype.process = function(fn, callback) {
var resource = this._prepare(fn, 'JSON');
var self = this;
return function() {
self._execute(resource, [].slice.call(arguments), 'JSON', callback)
};
};
Multithread.prototype.processInt32 = function(fn, callback) {
var resource = this._prepare(fn, 'Int32');
var self = this;
return function() {
self._execute(resource, [].slice.call(arguments), 'Int32', callback)
};
};
Multithread.prototype.processFloat64 = function(fn, callback) {
var resource = this._prepare(fn, 'Float64');
var self = this;
return function() {
self._execute(resource, [].slice.call(arguments), 'Float64', callback)
};
};
window['Multithread'] = Multithread;
}();
\ No newline at end of file
webserver/public/res/led-green.png

20.5 KiB

webserver/public/res/led-red.png

31.1 KiB

0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment