Każdy rozproszony system może zagwarantować tylko dwa z trzech następujących punktów:
(Basically Available, Soft state, Eventual consistency)
Hard real-time
Firm real-time
Soft real-time
Jeżeli dostęp do cache L1 zajmuje 1 sekundę to:
Bład przewidywania instrukcji warunkowych: 0:00:10
Odczyt z cache L2 : 0:00:14
Mutex lock/unlock : 0:00:50
Odczyt z pamięci RAM : 0:03:20
Kompresja ZIP 1kb danych : 1:40:00
Wysłanie 1kb przez sieć 1 Gbps : 5:33:20
Odczytanie losowe 4kb danych z SSD: 3 dni, 11:20:00
Jeżeli dostęp do cache L1 zajmuje 1 sekundę to:
Odczytanie sekwencyjne 1MB danych z dysku: 5 dni, 18:53:20
PING w obrębie jednej sieci : 11 dni, 13:46:40
Odczytanie sekwencyjnie 1MB danych z SSD : 23 dni, 3:33:20
Disk seek : 231 dni, 11:33:20
Odczytanie sekwencyjnie 1MB danych z dysku : 462 dni, 23:06:40
Wysłanie pakietu Kalifornia->Holadia->Kalifornia :
9 lat, 187 dni, 5:20:00
L2 | RAM | Dysk | Sieć | |
L1 | 5 | 83 | 13.666.666 | 80.000.000 |
L2 | 18 | 2.928.571 | 17.142.857 | |
RAM | 164.000 | 960.000 | ||
Dysk | 6 |
console.log("Hello World");
var fs = require("fs");
fs.readFile("example_log.txt", function (err, logData) {
if (err) {
throw err;
}
var text = logData.toString();
console.log(text);
});
var http = require("http");
var server = http.createServer(function (request, response) {
response.writeHead(200, {"Content-Type": "text/plain"});
response.end("Hello World\n");
});
server.listen(8000);
console.log("Server running at http://127.0.0.1:8000/");
var http = require("http");
var mysql = require("mysql");
var connection = mysql.createConnection({
user: "root",
password: "",
database: "db_name"
});
http.createServer(function (request, response) {
request.on("end", function () {
connection.query("SELECT * FROM your_table;", function (error, rows, fields) {
response.writeHead(200, { "Content-Type": "application/json" });
response.end(JSON.stringify(rows));
});
});
}).listen(8080);
var i, a, b, c, max;
max = 1000000000;
var time = process.hrtime();
for (i = 0; i < max; i++) {
a = 1234 + 5678 + i;
b = 1234 * 5678 + i;
c = 1234 / 2 + i;
}
var diff = process.hrtime(time);
console.log((diff[0] * 1e9 + diff[1]) / 1e6);
<?php
$a = $b = $c = $i = null;
$max = 1000000000;
$start = microtime(true);
for ($i = 0; $i < $max; $i++) {
$a = 1234 + 5678 + $i;
$b = 1234 * 5678 + $i;
$c = 1234 / 2 + $i;
}
$end = microtime(true);
var_dump(($end - $start) * 1000);
Czy takie testy są sensowne?
PHP 5.6.6 (VC11 x64)
Node v0.12.0 (x64)
Czy takie porównania mają sens?
Liczba iteracji
100
10,000
1,000,000
10,000,000
1,000,000,000
Node.js
0.008 ms
0.06 ms
1.5 ms
10 ms
943 ms
PHP
0.03 ms
1.44 ms
141 ms
1,429 ms
142,414 ms
function fibonacci(n) {
if (n < 2)
return 1;
else
return fibonacci(n-2) + fibonacci(n-1);
}
var time = process.hrtime();
console.log(fibonacci(40));
var diff = process.hrtime(time);
console.log((diff[0] * 1e9 + diff[1]) / 1e6);
<?php
function fibonacci($n) {
if ($n < 2) {
return 1;
} else {
return fibonacci($n - 2) + fibonacci($n - 1);
}
}
$start = microtime(true);
echo fibonacci(40);
$end = microtime(true);
var_dump(($end - $start) * 1000);
Czy takie testy są sensowne?
PHP 5.6.6 (VC11 x64)
Node v0.12.0 (x64)
Czy takie porównania mają sens?
Wartość n
10
30
40
45
Node.js
14 ms
26 ms
1,527 ms
16,782 ms
PHP
0.27 ms
473 ms
57,902 ms
640,945 ms
PHP / Node.js
x 0.019
x 18,2
x 37,9
x 38,2
<?php
$result = query($sql)
doSomething($result);
echo "Next command";
"use strict";
query(sql, function(result) {
doSomething(result);
});
console.log("Next command");
Siła tkwi w tym, że w obrębie JS to jest naturalne
<?php
$result = query($sql)
doSomething($result);
// waste of time
echo "Next command";
"use strict";
query(sql, function(result) {
doSomething(result);
});
console.log("Next command");
Porównajmy z:
Obsłużenie zapytania
Odpytanie bazy danych
Przetworzenie wyniku
Przygotowanie odpowiedzi
Wysłanie
odpowiedzi
Wątek 1
Wątek 2
Wątek 3
Wątek 4
Musimy brać pod uwagę narzut ze zmianą kontekstu oraz zwiększony poziom skomplikowania kodu jaki to generuje
Proces 1
Proces 2
Proces 3
Proces 4
Musimy brać pod uwagę wysoki koszt pamięci
Proces 1
System plików
Sieć
Baza danych
Inne
Pula wątków
Kolejka zdarzeń
Pętla zdarzeń
fs.readdir(source, function(err, files) {
if (err) {
console.log('Error finding files: ' + err)
} else {
files.forEach(function(filename, fileIndex) {
console.log(filename)
gm(source + filename).size(function(err, values) {
if (err) {
console.log('Error identifying file size: ' + err)
} else {
console.log(filename + ' : ' + values)
aspect = (values.width / values.height)
widths.forEach(function(width, widthIndex) {
height = Math.round(width / aspect)
console.log('resizing ' + filename + 'to ' + height + 'x' + height)
this.resize(width, height).write(destination + 'w' + width + '_' + filename, function(err) {
if (err) console.log('Error writing file: ' + err)
})
}.bind(this))
}
})
})
}
})
async.map(['file1','file2','file3'], fs.stat, function(err, results){
// results is now an array of stats for each file
});
async.filter(['file1','file2','file3'], fs.exists, function(results){
// results now equals an array of the existing files
});
async.parallel([
function(){ ... },
function(){ ... }
], callback);
async.series([
function(){ ... },
function(){ ... }
]);
var Q = require("q");
var FS = require("fs");
function getFile(name) {
var deferred = Q.defer();
FS.readFile(name, "utf-8", function (error, text) {
if (error) {
deferred.reject(new Error(error));
} else {
deferred.resolve(text);
}
});
return deferred.promise;
}
var file = getFile("foo.txt");
file.then(function(data) {
console.log('File has been read:', data);
})
.fail(function(err) {
console.error('Error received:', err);
})
var FS = require("fs");
var Q = require("q");
Q.nfcall(FS.readFile, "foo.txt", "utf-8")
.then(function(data) {
console.log('File has been read:', data);
})
.fail(function(err) {
console.error('Error received:', err);
})
.done();
Q.all([getFromDisk(), getFromCloud()]).spread(function (diskVal, cloudVal) {
assert(diskVal === cloudVal);
}).done();
promise.timeout(10000).then(
function (result) {
// will be called if the promise resolves normally
console.log(result);
},
function (err) {
// will be called if the promise is rejected, or the 10 second timeout occurs
console.log(err);
}
);
var EventEmitter = require("events").EventEmitter;
var door = new EventEmitter();
door.on("knockknock", function(guest) {
console.log(guest);
});
setInterval(function() {
door.emit("knockknock", "Boss");
}, 1000);
Benchmark.prototype.setup = function() {
var canvas = document.getElementById("canvas");
var canvasWidth = canvas.width;
var canvasHeight = canvas.height;
var ctx = canvas.getContext("2d");
var imageData = ctx.getImageData(0, 0, canvasWidth, canvasHeight);
var data = imageData.data;
var buf = new ArrayBuffer(imageData.data.length);
var buf8 = new Uint8ClampedArray(buf); //View for buf
var data32 = new Uint32Array(buf); //View for buf
};
Benchmark.prototype.teardown = function() {
ctx.putImageData(imageData, 0, 0);
};
var cluster = require("cluster");
var http = require("http");
var numCPUs = require("os").cpus().length;
if (cluster.isMaster) {
// Fork workers.
for (var i = 0; i < numCPUs; i++) {
cluster.fork();
}
cluster.on("exit", function(worker, code, signal) {
console.log("worker " + worker.process.pid + " died");
});
} else {
// Workers can share any TCP connection
// In this case its a HTTP server
http.createServer(function(req, res) {
res.writeHead(200);
res.end("hello world\n");
}).listen(8000);
}
function M(stdlib, foreign, heap) {
"use asm";
var i32 = new stdlib.Int32Array(heap);
var f64 = new stdlib.Float64Array(heap);
var imul = stdlib.Math.imul;
var truncate = foreign.truncate;
function foo() {
var a = 0; // a is signed
var b = 0.0; // b is double
a = i32[0]|0;
b = +f64[0];
return imul(a, truncate(b))|0;
}
return { foo: foo };
}
var module = M(window, {
truncate: function (x) {
return x | 0;
}
}, new ArrayBuffer(4 * 1024));
#include <stdio.h>
int fib(int x) {
if (x < 2) {
return 1;
} else {
return fib(x - 1) + fib(x - 2);
}
}
int main() {
int result = fib(45);
printf("Fib: %d\n", result);
return 1;
}
(Visual Studio 2013 z opcją /O2) - 5,288 ms
function __Z3fibi($x) {
$x = $x|0;
var $0 = 0, $1 = 0, $2 = 0, $3 = 0, $4 = 0, $5 = 0, $accumulator$tr$lcssa = 0,
$accumulator$tr1 = 0, $x$tr2 = 0, label = 0, sp = 0;
sp = STACKTOP;
$0 = ($x|0)<(2);
if ($0) {
$accumulator$tr$lcssa = 1;
} else {
$accumulator$tr1 = 1;$x$tr2 = $x;
while(1) {
$1 = (($x$tr2) + -1)|0;
$2 = (__Z3fibi($1)|0);
$3 = (($x$tr2) + -2)|0;
$4 = (($2) + ($accumulator$tr1))|0;
$5 = ($3|0)<(2);
if ($5) {
$accumulator$tr$lcssa = $4; break;
} else {
$accumulator$tr1 = $4;$x$tr2 = $3;
}
}
}
STACKTOP = sp;return ($accumulator$tr$lcssa|0);
}
16,050 ms
function asmCode(global, env, buffer) {
"use asm";
function fib(x) {
x = x|0;
if ((x >>> 0) < 2) return 1;
return ((fib((x-2)|0)|0) + (fib((x-1)|0)|0))|0;
}
return fib;
}
var fibModuleAsm = asmCode(window, {}, new ArrayBuffer(4 * 1024));
console.log(fibModuleAsm( 45 ));
8,695 ms
var a = SIMD.float32x4(1.0, 2.0, 3.0, 4.0);
var b = SIMD.float32x4(5.0, 6.0, 7.0, 8.0);
var c = SIMD.float32x4.add(a,b);
function simdAverage(src, len) {
var sumx4 = SIMD.float32x4.splat(0.0);
var srcx4 = new Float32x4Array(src.buffer);
for (var i = 0, n = len/4; i < n; ++i) {
sumx4 = SIMD.float32x4.add(sumx4, srcx4.getAt(i));
}
return (sumx4.x + sumx4.y + sumx4.z + sumx4.w) / len;
}
var server = http.createServer(function(request, response){});
var connections = [];
server.listen(8080, function(){});
var wsServer = new WebSocketServer({
httpServer: server,
});
wsServer.on("request", function(request) {
var connection = request.accept(null, request.origin);
connections.push(connection);
connection.send("Hello World!");
connection.on("message", function(message) {
parseMessage(message);
});
connection.on("close", function(connection) {
connections.forEach(function(connection) {
connection.send("Client disconnected");
});
});
});