PageRenderTime 27ms CodeModel.GetById 20ms RepoModel.GetById 1ms app.codeStats 0ms

/modules/_natives/fibers/README.md

https://github.com/teamdstn/dstnation
Markdown | 470 lines | 395 code | 75 blank | 0 comment | 0 complexity | 2ec3e9ff4aef684bff91aaefb5f86d80 MD5 | raw file
  1. fibers(1) -- Fiber support for v8 and Node
  2. ==========================================
  3. INSTALLING
  4. ----------
  5. ### via npm
  6. * `npm install fibers`
  7. * You're done!
  8. ### from source
  9. * `git clone git://github.com/laverdet/node-fibers.git`
  10. * `cd node-fibers`
  11. * `npm install`
  12. Note: node-fibers uses [node-gyp](https://github.com/TooTallNate/node-gyp) for
  13. building. To manually invoke the build process, you can use `node-gyp rebuild`.
  14. This will put the compiled extension in `build/Release/fibers.node`. However,
  15. when you do `require('fibers')`, it will expect the module to be in, for
  16. example, `bin/linux-x64-v8-3.11/fibers.node`. You can manually put the module
  17. here every time you build, or you can use the included build script. Either
  18. `npm install` or `node build -f` will do this for you. If you are going to be
  19. hacking on node-fibers, it may be worthwhile to first do `node-gyp configure`
  20. and then for subsequent rebuilds you can just do `node-gyp build` which will
  21. be faster than a full `npm install` or `node-gyp rebuild`.
  22. ### important!
  23. It's recommended that you use node 0.6.18 or higher with node-fibers. Using
  24. other versions may lead to instability during high loads.
  25. ### using windows 8?
  26. Windows 8 is a beta operating system and you may have issues with fibers. To use
  27. fibers in Windows 8 you may need to run node.exe in Windows 7 compatibility
  28. mode. Once Windows 8 is released this issue will be revisited. See gh-70 for
  29. more information.
  30. ### other notes
  31. Unlike most NodeJS projects, node-fibers is a C++ project. Some extra work is
  32. required to compile node-fibers, but pretty much every platform is supported
  33. in some way. Binary distributions in 32 and 64-bit forms are provided in npm for
  34. Linux, OS X, and Windows (special thanks to
  35. [Jeroen Janssen](https://github.com/japj) for his work on fibers in Windows).
  36. Support for Solaris, FreeBSD, and OpenBSD is provided by compiling the extension
  37. on your system during install time via
  38. [node-gyp](https://github.com/TooTallNate/node-gyp). If your operating system
  39. isn't listed here you may have luck copying the build process for one of the
  40. other OS's, assuming you are running a POSIX-like OS.
  41. node 0.6.x is required to run this release of node-fibers. Older versions of
  42. node (0.4.x) are supported in older releases of node-fibers. See the 0.5.x
  43. branch of node-fibers for documentation.
  44. EXAMPLES
  45. --------
  46. The examples below describe basic use of `Fiber`, but note that it is **not
  47. recommended** to use `Fiber` without an abstraction in between your code and
  48. fibers. See "FUTURES" below for additional information.
  49. ### Sleep
  50. This is a quick example of how you can write sleep() with fibers. Note that
  51. while the sleep() call is blocking inside the fiber, node is able to handle
  52. other events.
  53. $ cat sleep.js
  54. ```javascript
  55. var Fiber = require('fibers');
  56. function sleep(ms) {
  57. var fiber = Fiber.current;
  58. setTimeout(function() {
  59. fiber.run();
  60. }, ms);
  61. Fiber.yield();
  62. }
  63. Fiber(function() {
  64. console.log('wait... ' + new Date);
  65. sleep(1000);
  66. console.log('ok... ' + new Date);
  67. }).run();
  68. console.log('back in main');
  69. ```
  70. $ node sleep.js
  71. wait... Fri Jan 21 2011 22:42:04 GMT+0900 (JST)
  72. back in main
  73. ok... Fri Jan 21 2011 22:42:05 GMT+0900 (JST)
  74. ### Incremental Generator
  75. Yielding execution will resume back in the fiber right where you left off. You
  76. can also pass values back and forth through yield() and run(). Again, the node
  77. event loop is never blocked while this script is running.
  78. $ cat generator.js
  79. ```javascript
  80. var Fiber = require('fibers');
  81. var inc = Fiber(function(start) {
  82. var total = start;
  83. while (true) {
  84. total += Fiber.yield(total);
  85. }
  86. });
  87. for (var ii = inc.run(1); ii <= 10; ii = inc.run(1)) {
  88. console.log(ii);
  89. }
  90. ```
  91. $ node generator.js
  92. 1
  93. 2
  94. 3
  95. 4
  96. 5
  97. 6
  98. 7
  99. 8
  100. 9
  101. 10
  102. ### Fibonacci Generator
  103. Expanding on the incremental generator above, we can create a generator which
  104. returns a new Fibonacci number with each invocation. You can compare this with
  105. the [ECMAScript Harmony
  106. Generator](http://wiki.ecmascript.org/doku.php?id=harmony:generators) Fibonacci
  107. example.
  108. $ cat fibonacci.js
  109. ```javascript
  110. var Fiber = require('fibers');
  111. // Generator function. Returns a function which returns incrementing
  112. // Fibonacci numbers with each call.
  113. function Fibonacci() {
  114. // Create a new fiber which yields sequential Fibonacci numbers
  115. var fiber = Fiber(function() {
  116. Fiber.yield(0); // F(0) -> 0
  117. var prev = 0, curr = 1;
  118. while (true) {
  119. Fiber.yield(curr);
  120. var tmp = prev + curr;
  121. prev = curr;
  122. curr = tmp;
  123. }
  124. });
  125. // Return a bound handle to `run` on this fiber
  126. return fiber.run.bind(fiber);
  127. }
  128. // Initialize a new Fibonacci sequence and iterate up to 1597
  129. var seq = Fibonacci();
  130. for (var ii = seq(); ii <= 1597; ii = seq()) {
  131. console.log(ii);
  132. }
  133. ```
  134. $ node fibonacci.js
  135. 0
  136. 1
  137. 1
  138. 2
  139. 3
  140. 5
  141. 8
  142. 13
  143. 21
  144. 34
  145. 55
  146. 89
  147. 144
  148. 233
  149. 377
  150. 610
  151. 987
  152. 1597
  153. ### Basic Exceptions
  154. Fibers are exception-safe; exceptions will continue travelling through fiber
  155. boundaries:
  156. $ cat error.js
  157. ```javascript
  158. var Fiber = require('fibers');
  159. var fn = Fiber(function() {
  160. console.log('async work here...');
  161. Fiber.yield();
  162. console.log('still working...');
  163. Fiber.yield();
  164. console.log('just a little bit more...');
  165. Fiber.yield();
  166. throw new Error('oh crap!');
  167. });
  168. try {
  169. while (true) {
  170. fn.run();
  171. }
  172. } catch(e) {
  173. console.log('safely caught that error!');
  174. console.log(e.stack);
  175. }
  176. console.log('done!');
  177. ```
  178. $ node error.js
  179. async work here...
  180. still working...
  181. just a little bit more...
  182. safely caught that error!
  183. Error: oh crap!
  184. at error.js:11:9
  185. done!
  186. FUTURES
  187. -------
  188. Using the `Fiber` class without an abstraction in between your code and the raw
  189. API is **not recommended**. `Fiber` is meant to implement the smallest amount of
  190. functionality in order make possible many different programming patterns. This
  191. makes the `Fiber` class relatively lousy to work with directly, but extremely
  192. powerful when coupled with a decent abstraction. There is no right answer for
  193. which abstraction is right for you and your project. Included with `node-fibers`
  194. is an implementation of "futures" which is fiber-aware. Usage of this library
  195. is documented below. There are several other externally-maintained options
  196. which can be found on the [wiki](https://github.com/laverdet/node-fibers/wiki).
  197. You **should** feel encouraged to be creative with fibers and build a solution
  198. which works well with your project. For instance, `Future` is not a good
  199. abstraction to use if you want to build a generator function (see Fibonacci
  200. example above).
  201. Using `Future` to wrap existing node functions. At no point is the node event
  202. loop blocked:
  203. $ cat ls.js
  204. ```javascript
  205. var Future = require('fibers/future'), wait = Future.wait;
  206. var fs = require('fs');
  207. // This wraps existing functions assuming the last argument of the passed
  208. // function is a callback. The new functions created immediately return a
  209. // future and the future will resolve when the callback is called (which
  210. // happens behind the scenes).
  211. var readdir = Future.wrap(fs.readdir);
  212. var stat = Future.wrap(fs.stat);
  213. Fiber(function() {
  214. // Get a list of files in the directory
  215. var fileNames = readdir('.').wait();
  216. console.log('Found '+ fileNames.length+ ' files');
  217. // Stat each file
  218. var stats = [];
  219. for (var ii = 0; ii < fileNames.length; ++ii) {
  220. stats.push(stat(fileNames[ii]));
  221. }
  222. wait(stats);
  223. // Print file size
  224. for (var ii = 0; ii < fileNames.length; ++ii) {
  225. console.log(fileNames[ii]+ ': '+ stats[ii].get().size);
  226. }
  227. }).run();
  228. ```
  229. $ node ls.js
  230. Found 11 files
  231. bin: 4096
  232. fibers.js: 1708
  233. .gitignore: 37
  234. README.md: 8664
  235. future.js: 5833
  236. .git: 4096
  237. LICENSE: 1054
  238. src: 4096
  239. ls.js: 860
  240. Makefile: 436
  241. package.json: 684
  242. The future API is designed to make it easy to move between classic
  243. callback-style code and fiber-aware waiting code:
  244. $ cat sleep.js
  245. ```javascript
  246. var Future = require('fibers/future'), wait = Future.wait;
  247. // This function returns a future which resolves after a timeout. This
  248. // demonstrates manually resolving futures.
  249. function sleep(ms) {
  250. var future = new Future;
  251. setTimeout(function() {
  252. future.return();
  253. }, ms);
  254. return future;
  255. }
  256. // You can create functions which automatically run in their own fiber and
  257. // return futures that resolve when the fiber returns (this probably sounds
  258. // confusing.. just play with it to understand).
  259. var calcTimerDelta = function(ms) {
  260. var start = new Date;
  261. sleep(ms).wait();
  262. return new Date - start;
  263. }.future(); // <-- important!
  264. // And futures also include node-friendly callbacks if you don't want to use
  265. // wait()
  266. calcTimerDelta(2000).resolve(function(err, val) {
  267. console.log('Set timer for 2000ms, waited '+ val+ 'ms');
  268. });
  269. ```
  270. $ node sleep.js
  271. Set timer for 2000ms, waited 2009ms
  272. API DOCUMENTATION
  273. -----------------
  274. Fiber's definition looks something like this:
  275. ```javascript
  276. /**
  277. * Instantiate a new Fiber. You may invoke this either as a function or as
  278. * a constructor; the behavior is the same.
  279. *
  280. * When run() is called on this fiber for the first time, `fn` will be
  281. * invoked as the first frame on a new stack. Execution will continue on
  282. * this new stack until `fn` returns, or Fiber.yield() is called.
  283. *
  284. * After the function returns the fiber is reset to original state and
  285. * may be restarted with another call to run().
  286. */
  287. function Fiber(fn) {
  288. [native code]
  289. }
  290. /**
  291. * `Fiber.current` will contain the currently-running Fiber. It will be
  292. * `undefined` if there is no fiber (i.e. the main stack of execution).
  293. *
  294. * See "Garbage Collection" for more information on responsible use of
  295. * `Fiber.current`.
  296. */
  297. Fiber.current = undefined;
  298. /**
  299. * `Fiber.yield()` will halt execution of the current fiber and return control
  300. * back to original caller of run(). If an argument is supplied to yield(),
  301. * run() will return that value.
  302. *
  303. * When run() is called again, yield() will return.
  304. *
  305. * Note that this function is a global to allow for correct garbage
  306. * collection. This results in no loss of functionality because it is only
  307. * valid to yield from the currently running fiber anyway.
  308. *
  309. * Note also that `yield` is a reserved word in Javascript. This is normally
  310. * not an issue, however some code linters may complain. Rest assured that it
  311. * will run fine now and in future versions of Javascript.
  312. */
  313. Fiber.yield = function(param) {
  314. [native code]
  315. }
  316. /**
  317. * run() will start execution of this Fiber, or if it is currently yielding,
  318. * it will resume execution. If an argument is supplied, this argument will
  319. * be passed to the fiber, either as the first parameter to the main
  320. * function [if the fiber has not been started] or as the return value of
  321. * yield() [if the fiber is currently yielding].
  322. *
  323. * This function will return either the parameter passed to yield(), or the
  324. * returned value from the fiber's main function.
  325. */
  326. Fiber.prototype.run = function(param) {
  327. [native code]
  328. }
  329. /**
  330. * reset() will terminate a running Fiber and restore it to its original
  331. * state, as if it had returned execution.
  332. *
  333. * This is accomplished by causing yield() to throw an exception, and any
  334. * futher calls to yield() will also throw an exception. This continues
  335. * until the fiber has completely unwound and returns.
  336. *
  337. * If the fiber returns a value it will be returned by reset().
  338. *
  339. * If the fiber is not running, reset() will have no effect.
  340. */
  341. Fiber.prototype.reset = function() {
  342. [native code]
  343. }
  344. /**
  345. * throwInto() will cause a currently yielding fiber's yield() call to
  346. * throw instead of return gracefully. This can be useful for notifying a
  347. * fiber that you are no longer interested in its task, and that it should
  348. * give up.
  349. *
  350. * Note that if the fiber does not handle the exception it will continue to
  351. * bubble up and throwInto() will throw the exception right back at you.
  352. */
  353. Fiber.prototype.throwInto = function(exception) {
  354. [native code]
  355. }
  356. ```
  357. GARBAGE COLLECTION
  358. ------------------
  359. If you intend to build generators, iterators, or "lazy lists", you should be
  360. aware that all fibers must eventually unwind. This is implemented by causing
  361. yield() to throw unconditionally when the library is trying to unwind your
  362. fiber-- either because reset() was called, or all handles to the fiber were lost
  363. and v8 wants to delete it.
  364. Something like this will, at some point, cause an infinite loop in your
  365. application:
  366. ```javascript
  367. var fiber = Fiber(function() {
  368. while (true) {
  369. try {
  370. Fiber.yield();
  371. } catch(e) {}
  372. }
  373. });
  374. fiber.run();
  375. ```
  376. If you either call reset() on this fiber, or the v8 garbage collector decides it
  377. is no longer in use, the fiber library will attempt to unwind the fiber by
  378. causing all calls to yield() to throw. However, if you catch these exceptions
  379. and continue anyway, an infinite loop will occur.
  380. There are other garbage collection issues that occur with misuse of fiber
  381. handles. If you grab a handle to a fiber from within itself, you should make
  382. sure that the fiber eventually unwinds. This application will leak memory:
  383. ```javascript
  384. var fiber = Fiber(function() {
  385. var that = Fiber.current;
  386. Fiber.yield();
  387. }
  388. fiber.run();
  389. fiber = undefined;
  390. ```
  391. There is no way to get back into the fiber that was started, however it's
  392. impossible for v8's garbage collector to detect this. With a handle to the fiber
  393. still outstanding, v8 will never garbage collect it and the stack will remain in
  394. memory until the application exits.
  395. Thus, you should take care when grabbing references to `Fiber.current`.