Asynchronous I/O in NodeJS - new standard or challenges?

4,709 views

Published on

Published in: Technology, Design
1 Comment
8 Likes
Statistics
Notes
No Downloads
Views
Total views
4,709
On SlideShare
0
From Embeds
0
Number of Embeds
23
Actions
Shares
0
Downloads
96
Comments
1
Likes
8
Embeds 0
No embeds

No notes for slide

Asynchronous I/O in NodeJS - new standard or challenges?

  1. 1. Asynchronous I/O in NodeJS - Standard and challenge of web programming? Pham Cong Dinh @ SkunkWorks @pcdinh BarCamp Saigon 2011 Follow us on Twitter: @teamskunkworks
  2. 2. Notice <ul><li>It is not a comprehensive study
  3. 3. Things can be changed
  4. 4. No standard at the moment
  5. 5. Unix only </li></ul>
  6. 6. Proven control flow models <ul><li>Single-threaded process model </li><ul><li>Prefork MPM Apache HTTPd </li></ul><li>Multi-threaded process model </li><ul><li>Worker MPM Apache HTTPd
  7. 7. JVM </li></ul></ul>
  8. 8. Emerging control flow models <ul><li>Coroutines </li></ul>Coroutines are computer program components that generalize subroutines to allow multiple entry points for suspending and resuming execution at certain locations. <ul><li>Fiber </li></ul>A lightweight thread of execution. Like threads, fibers share address space. However, fibers use co-operative multitasking while threads use pre-emptive multitasking. <ul><li>Events: non-blocking I/O </li></ul>
  9. 9. Events / Non-blocking I/O From http://bethesignal.org/
  10. 10. Request handling: Process / Threads / Events <ul><li>Process: A single process is forked per request. That process is blocked until response can be produced
  11. 11. Threads: A process contains multiple threads. A single thread is assigned to handle an incoming request. Thread-per-request model
  12. 12. Events: A process consists of the processing of a series of events. At any instant in time, a single event/request is being processed. The process is not blocked on I/O request. </li></ul>
  13. 13. Request handling: Process / Threads / Events Threads shares ● D efault share memor y ● F ile descriptors ● Filesystem context ● Signals and S ignal handling
  14. 14. Request handling: Process / Threads / Events Thread creation is expensive - From iobound.com
  15. 15. Request handling: Process / Threads / Events Context switching is expensive
  16. 16. Request handling: Process / Threads / Events Blocking model: Process and Threads
  17. 17. Request handling: Process / Threads / Events Non-blocking model: Events
  18. 18. Request handling: Event-driven IO loop issue poll vs. epoll epoll: O(1) or O(n=active)
  19. 19. Request handling: Event-driven callback issues Non-blocking IO Loop vs. Blocking callback Event dispatching is not blocked Callback can be blocked Mixing asynchronous code and synchronous code can be bad
  20. 20. Events in NodeJS <ul><li>libev for event loops
  21. 21. libeio for asynchonous file I/O
  22. 22. c-ares for asynchronous DNS requests and name resolution.
  23. 23. evcom (by Ryan Dahl) is a stream socket library on top of libev. </li></ul>
  24. 24. Asynchronous programming model in NodeJS <ul><li>First citizen: High order function/callback
  25. 25. Most “objects” in NodeJS are Event Emitters (http server/client, etc.)
  26. 26. Most low level “functions” take callbacks. (posix API, DNS lookups, etc.) </li></ul>Blocking code var a = db.query('SELECT A'); console.log('result a:', a); Non-blocking code using callback db.query('SELECT A', function(result) { console.log('result a:', result); });
  27. 27. Asynchronous programming model in NodeJS <ul><li>Callbacks is hard </li><ul><li>Divides things into stages and handle each stage in a a callback
  28. 28. Do things in a specific order.
  29. 29. You must keep track of what is done at a point of time
  30. 30. Hard to handle failures
  31. 31. Nested callbacks can be hard to read </li></ul></ul>
  32. 32. Asynchronous programming model in NodeJS <ul><li>Nested callbacks can be hard to read </li></ul>var transferFile = function (request, response) { var uri = url.parse(request.url).pathname; var filepath = path.join(process.cwd(), uri); // check whether the file is exist and get the result from callback path.exists(filepath, function (exists) { if (!exists) { response.writeHead(404, {&quot;Content-Type&quot;: &quot;text/plain&quot;}); response.write(&quot;404 Not Foundn&quot;); response.end(); } else { // read the file content and get the result from callback fs.readFile(filepath, &quot;binary&quot;, function (error, data) { if (error) { response.writeHead(500, {&quot;Content-Type&quot;: &quot;text/plain&quot;}); response.write(error + &quot;n&quot;); } else { response.writeHead(200); response.write(data, &quot;binary&quot;); } response.end(); }); } }); }
  33. 33. Asynchronous programming model in NodeJS <ul><li>Callback is hard to debug </li></ul>function f () { throw new Error(’foo’); } setTimeout(f, 10000*Math.random()); setTimeout(f, 10000*Math.random()); From which line does the error arise?
  34. 34. Asynchronous programming model in NodeJS Flow Control Libraries <ul><li>Steps https://github.com/creationix/step
  35. 35. Flow-JS https://github.com/willconant/flow-js
  36. 36. Node-Promise https://github.com/kriszyp/node-promise </li></ul>
  37. 37. Asynchronous programming model in NodeJS Flow Control Libraries: Steps <ul><li>Step's goal is to both remove boilerplate code and to improve readability of asynchronous code. The features are easy chaining of serial actions with optional parallel groups within each step. </li></ul>Step( function readSelf() { fs.readFile(__filename, this); }, function capitalize(err, text) { if (err) throw err; return text.toUpperCase(); }, function showIt(err, newText) { if (err) throw err; console.log(newText); } );
  38. 38. Asynchronous programming model in NodeJS Flow Control Libraries: Flow-JS <ul><li>Flow-JS provides a Javascript construct that is something like a continuation or a fiber found in other languages. Practically speaking, it can be used to eliminate so-called &quot;pyramids&quot; from your multi-step asynchronous logic. </li></ul>dbGet('userIdOf:bobvance', function(userId) { dbSet('user:' + userId + ':email', 'bobvance@potato.egg', function() { dbSet('user:' + userId + ':firstName', 'Bob', function() { dbSet('user:' + userId + ':lastName', 'Vance', function() { okWeAreDone(); }); }); }); }); Asynchronous programming model in NodeJS Flow Control Libraries: Flow-JS flow.exec( function() { dbGet('userIdOf:bobvance', this); }, function(userId) { dbSet('user:' + userId + ':email', 'bobvance@potato.egg', this.MULTI()); dbSet('user:' + userId + ':firstName', 'Bob', this.MULTI()); dbSet('user:' + userId + ':lastName', 'Vance', this.MULTI()); }, function() { okWeAreDone() } );
  39. 39. Asynchronous programming model in NodeJS JavaScript extension: TameJS <ul><li>Tame (or &quot;TameJs&quot;) is an extension to JavaScript, written in JavaScript, that makes event programming easier to write, read, and edit when control-flow libraries are not good enough!.
  40. 40. http://tamejs.org/ </li></ul>
  41. 41. Asynchronous programming model in NodeJS JavaScript extension: TameJS <ul><li>Synchronous code </li></ul>handleVisit : function(angel, buffy) { var match_score = getScore(angel, buffy); var next_match = getNextMatch(angel); var visit_info = recordVisitAndGetInfo(angel, buffy); if (match_score > 0.9 && ! visit_info.last_visit) { sendVisitorEmail(angel, buffy); } doSomeFinalThings(match_score, next_match, visit_info); } <ul><li>Asynchrnous code </li></ul>handleVisit : function(angel, buffy) { getScore(angel, buffy, function(match_score) { getNextMatch(angel, function(next_match) { recordVisitAndGetInfo(angel, buffy, function(visit_info) { if (match_score > 0.9 && ! visit_info.last_visit) { sendVisitorEmail(angel, buffy); } doSomeFinalThings(match_score, next_match, visit_info); }); }); }); }
  42. 42. Asynchronous programming model in NodeJS JavaScript extension: TameJS <ul><li>TameJS style </li></ul>handleVisit : function(angel, buffy) { // // let's fire all 3 at once // await { getScore (angel, buffy, defer (var score)); getNextMatch (angel, buffy, defer (var next)); recordVisitAndGetInfo (angel, buffy, defer (var vinfo)); } // // they've called back, and now we have our data // if (score > 0.9 && ! vinfo.last_visit) { sendVisitorEmail(angel, buffy); } doSomeFinalThings(score, next, vinfo); }
  43. 43. Asynchronous programming model in NodeJS JavaScript's yield <ul><li>V8/NodeJS has not supported yield, so generator yet </li></ul>
  44. 44. The end <ul><li>Q & A </li></ul>

×