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)) } }) }) } })
Nice try, but not enough
Communicating Sequential Processes
Independent logical threads of execution
go(function*() { yield sleep(1000); return 1; });
Lightweight processes
Mechanism: channels
Synchronization
Queue
var value = yield take(ch);
var stillOpen = yield put(ch, value);
var r = yield alts([ch1, ch2, [ch3, value]]); if (r.channel === ch1) { ... }
// Fastest bidder wins yield alts([fromClient1, fromClient2, fromClient3]);
for (;;) { yield alts([keydowns, timeout(50)]); console.log("Type faster!"); }
for (;;) { yield alts([pings, timeout(5000)]); console.log("Client hasn't pinged us for 5 seconds!"); }
Slow down fast producer by using a fixed-size buffer to avoid saturating consumer
Avoid sending too many emails on repeated failures
go(function*() { for (var t = timeout(60000);;) { for (var count = 0;;count++) { var r = yield alts([errors, t]); if (r.channel === t) { if (count > 0) { yield put(mails, count + " errors in the last 60 seconds"); } break; } } } });
go(function*() { for (;;) { var value = yield take(control); if (value === "off") { continue; } for (;;) { var r = yield alts([control, works]) if (r.channel === works) { doWork(r.value); } else { if (value === "off") { break; } } } } }); // In other places yield put(control, "on"); yield put(control, "off");
Encapsulated in the process
Combined with the previous => serialized access to local state
Each process handles a single task
Behaviors vs. data: processes vs. channels
With normal programming construct: conditionals, loops, exceptions
Long-running processes handle repeated signals
Wire channels to fake generated data and logging instead of real IO
Again this comes to channels being a sequence of things, not individual things
The cost is paid per-process, not per-signal
putAsync
, takeAsync
yield
is 2-way communication
For js/py CSP
Channels on both side
Channels on all tabs
ubolonton on Github, LinkedIn, Skype, Facebook, Twitter, Google+…
Any question, comment, feedback, or correction is welcome.