Open source JavaScript engine, developed by Google, shipped with Google Chrome browser.
Compiles JavaScript to native machine code instead of executing bytecode or interpreting it.
Employs optimization techniques for better performance.
result = db.query("select * from T"); // use result
result = db.query("select * from T"); // use result
In many cases, just waiting for the response.
L1: 3 cycles
L2: 14 cycles
RAM: 250 cycles
-----------------------
DISK: 41,000,000 cycles
NETWORK: 240,000,000 cycles
http://duartes.org/gustavo/blog/post/what-your-computer-does-while-you-wait
"Non-blocking"
L1, L2, RAM
-----------------------
"Blocking"
DISK, NETWORK
Better software can multitask.
Other threads of execution can run while waiting.
Apache uses one thread per connection.
NGINX doesn't use threads. It uses an event loop.
A loop that waits for events (I/O availability, timeout, UI interaction, ...).
When an event is available, it will be processed by executing a callback.
For massive concurrency, cannot use an OS thread for each connection.
- In systems programming, threads are a necessary evil.
- In application programming, threads are just evil.
- Threads provide a deceptively simple model of concurrency.
- Threads are subject to races and deadlocks.
Semaphore, Monitor, Rendezvous, Synchronization
- This used to be operating system stuff.
- It has leaked into applications because of networking and the multi-core problem.
Code like this:
result = query("select..."); // use result
either blocks the entire OS thread or implies multiple execution stacks.
But a code like this:
query("select...", function (result) { // use result });
allows the program to return to the event loop immediately.
query("select...", function (result) { // use result });
For reasons both cultural and infrastructural.
We're tought I/O with this:
puts("Enter your name: "); name = gets(); puts("Name: " + name);
We're tought to demand input and do nothing until we have it.
Code like
puts("Enter your name: "); gets(function (name) { puts("Name: " + name); });
is rejected as too complicated.
So why isn't everyone using event loops?
Single threaded event loops require I/O to be non-blocking.
Most libraries are not.
libmysql_client
) do not provide support for asynchronous queriesEventMachine, Twisted, AnyEvent provide very good event platforms.
Easy to create efficent servers.
But users are confused how to combine with other available libraries.
Users still require expert knowledge of event loops, non-blocking I/O.
JavaScript designed specifically to be used with an event loop:
The culture of JavaScript is already geared towards evented programming.
To provide a purely evented, non-blocking infrastructure to script highly concurrent programs.
Created by Ryan Dahl
Sponsored by Joyent
September 3, 2011 https://github.com/popular/watched
console.log('hello world');
setTimeout(function() { console.log('world'); }, 2000); console.log('hello');
setTimeout(function() { console.log('world'); }, 2000); console.log('hello');
A program which prints "hello", waits 2 seconds, outputs "world", and then exits.
Node exits automatically when there is nothing else to do.
Change the "hello world" program to loop forever, but print an exit message when the user kills it.
Special object process
and SIGINT
signal should be used.
setInterval(function() { console.log('hello'); }, 500); process.addListener('SIGINT', function() { console.log('goodbye'); process.exit(0); });
The process
object emits an event when it receives a signal. Like in the DOM, you need only to add a listener to catch them.
Write a program which resolves google.com and prints its IP addresses.
Built-in module called dns
is for working with DNS.
Resolving DNS takes some time but a lot of APIs let you think things happen instantly.
We can allow the program to continue while it waits for the response.
var dns = require('dns'); console.log('resolving google.com...'); dns.resolve('google.com', function (err, addresses) { if (err) { throw err; } console.log('found: ', addresses); });
It runs very quickly. But millions of clock cycles passed.
We can't perceive 2 microseconds.
In a server environment, since handling many clients, waiting millions of clock cycles is wasteful.
var http = require('http'); var s = http.createServer(function (req, res) { res.writeHead(200); res.end('hello world\n'); }); // listen on port 8000 s.listen(8000);
var http = require('http'); http.createServer(function (req, res) { res.writeHead(200); setTimeout(function () { res.end('world\n'); }, 2000); res.write('hello\n'); }).listen(8000);
http://localhost:8000/yahoo.com
should return:
Requestingquery: yahoo.com
["98.137.149.56","209.191.122.70","67.195.160.76"]
http://localhost:8000/google.com
should return:
query: google.com
["74.125.39.99","74.125.39.103","74.125.39.104"]
var http = require('http'); var dns = require('dns'); http.createServer(function (req, res) { var query = req.url.replace('/', ''); res.write('query: ' + query + '\n'); dns.resolve(query, function (err, addresses) { res.end(JSON.stringify(addresses) + '\n'); }); }).listen(8000);
The overhead of each connection is low so the server is able to achive good concurrency: it juggles many connections at a time.
Write a program which:
var net = require('net'); net.createServer(function (socket) { socket.end('Goodbye\n'); }).listen(8000);
var net = require('net'); var people = []; net.createServer(function (socket) { people.push(socket); socket.on('data', function (data) { people.forEach(function (person) { if (person != socket && person.writable) person.write(data); }); }); }).listen(8000);
var http = require('http'); // ... TCP chat server code omitted // ... it is listening on 8000 http.createServer(function (req, res) { res.writeHead(200); people.push(res); }).listen(8001);
A single process is listening on both 8000 and 8001 ports, and everything is handled because node.js has non-blocking I/O.
npm
is a package manager for node. You can use it to install and publish your node programs. It manages dependencies and does other cool stuff.
curl http://npmjs.org/install.sh | sh
npm install -g connect
var connect = require('connect'); connect.createServer( connect.static(__dirname + '/public'), connect.favicon(), connect.logger(), connect.errorHandler(), connect.bodyParser(), connect.cookieParser(), connect.session({'secret': 'password'}) ).listen(8000);
var express = require('express'); var app = express.createServer(); app.get('/', function(req, res){ res.send('Hello World'); }); app.listen(3000);
Node.js is inherently single threaded (and arguably JavaScript too).
Single threaded means that a Node process can only use one core.
Node is good at concurrency, but how to run code in parallel with it?
Node's focus on asynchronous networking makes IPC easy, and thus parallel programming easy.
var w = new Worker('fib.js'); w.postMessage({ calculate: 10 }); w.onmessage = function(m) { console.log('result: %j', m); w.terminate(); };
Effectively allowes the kernel to load balance connections across processes.
var http = require('http'); var net = require('net'); // Create a web server var web = http.Server(function (req, res) { res.writeHead(200); res.end('hello world\n'); }); web.listen(8000); // File Descriptor server net.Server(function (c) { c.write('blah', 'ascii', web.fd); c.end(); }).listen('/tmp/node_server.sock');
var http = require('http'); var net = require('net'); var web = http.Server(function (req, res) { res.writeHead(200); res.end('hello from ' + process.pid + '\n'); }); var c = net.createConnection('/tmp/node_server.sock'); c.on('fd', function (fd) { web.listenFD(fd); });
Extensible multi-core server management for nodejs.
Questions?
Presentation powered by Shower