Skip to content
This repository has been archived by the owner on Aug 31, 2018. It is now read-only.

Bring true coroutines(fiber) to ayo in core code? #19

Open
yuu2lee4 opened this issue Aug 25, 2017 · 27 comments
Open

Bring true coroutines(fiber) to ayo in core code? #19

yuu2lee4 opened this issue Aug 25, 2017 · 27 comments

Comments

@yuu2lee4
Copy link

Like fibjs did?

@benjamingr
Copy link
Contributor

Fibers are largely superseded by async/await and solve a problem ayo doesn't really have.

@ShiningRay
Copy link

Actually, I don't want to write extra keywords in code.

@yuu2lee4
Copy link
Author

@benjamingr Fibers‘s performance is much better than async/await and it has no infection.

@yuu2lee4
Copy link
Author

@ShiningRay you needn't write extra keywords in code if you know how it works.

@benjamingr
Copy link
Contributor

Fibers are not faster, look at the benchmarks bluebird always beat fibers since 2013.

Also, we should stick with standard approaches (promises/async await) rather than go against the language specification.

@zkat
Copy link
Contributor

zkat commented Aug 25, 2017

As a former fibers user, I too believe that async/await has essentially supplanted fibers: and async/await has the advantage that it does not need additional VM-level work from the project, and fits neatly into other components of the language (specially Promises, which are now quite widespread), making it more compatible with the existing ecosystem.

That's my 2c at least :)

@Qard
Copy link
Member

Qard commented Aug 25, 2017

Yeah, the interop of async/await with all existing promise-based code is a huge advantage. Fibers are neat but ultimately incompatible with the vast majority of existing modules.

@ngot
Copy link

ngot commented Aug 26, 2017

Maybe there is some misunderstanding of Fiber.Here is our benchmark 2 years ago, which shows Fiber has much much much better performance than the current model of Node.js. Here is the benchmark report https://github.com/fibjs/fibjs/blob/master/perf/http_server/performance-en.md

@Fishrock123
Copy link
Contributor

2 years ago is a long time - performance just radically changed across the board in V8 with the new Turbofan JIT...

@Qard
Copy link
Member

Qard commented Aug 26, 2017

Fibers are technically capable of better performance, being a lower-level concept than async/await, but I think the flexibility/interop advantages of async/await far outweighs any slight perf boost you might get from fibers. It's likely async/await could be optimized enough to effectively be fibers internally anyway.

@zkat
Copy link
Contributor

zkat commented Aug 26, 2017

@ngot oof. Those benchmarks are against v0.10. You might wanna update this to compare against the latest master. That is an ancient node by current standards, not even counting Turbofan, as @Fishrock123 said

@ngot
Copy link

ngot commented Aug 26, 2017

The benchmark was 2 years ago, I'll run a benchmark recently and update the result. But before that I can say something I can conclude.

In the previous benchmark, it shows fibjs is 14 times faster than nodejs when QPS is 100K. At that time, nodejs don't have "turbofan", neither the fibjs.

Actually, now the benchmark node.js probably perform much slower than before, because the previous tests are based on simply callback mode(only libuv), now if we test with promise/async, it will be 100+ times slower than callback mode.

Anyway, you can always run the benchmark on your own using any version of node to prove this.

Like @Qard said, Fibers are technically capable of better performance and it will get much much faster with the correct optimizing.

@benjamingr I'm confusing that you are comparing Fiber with bluebird. They are like apples and oranges. IMO, you should compare fiber with libuv.

In Node.js, the real process of async/promise is: libuv + v8(async/promise), while in fibjs, the process is only fiber. Now the fiber is faster than libuv. When talking about the performance of fiber, it's not related to how fast async/promise is.

@ngot
Copy link

ngot commented Aug 26, 2017

Here is a very simple benchmark under the newest version of both Node.js & fibjs.

benchmark.js

const fs = require('fs');

const isFiber = typeof module === 'undefined';
const num = 100000;

if (isFiber) {
  console.time('fiber');
  for (let i = 0; i < num; i++) {
    fs.readFile(__filename);
  }
  console.timeEnd('fiber');
} else {
  const promisify = require('util').promisify;
  const readFile = promisify(fs.readFile);

  (async () => {
    console.time('async');
    for (let i = 0; i < num; i++) {
      await readFile(__filename);
    }
    console.timeEnd('async');
  })();
}

the result on my Macbook Pro 15 is:

➜ node -v
v8.4.0
➜ node benchmark.js
async: 5271.769ms
➜ fibjs -v
v0.11.0
➜ fibjs benchmark.js
fiber: 919.061ms

Fiber is almost 6x faster than event+async at this condition.

@zkat
Copy link
Contributor

zkat commented Aug 26, 2017

This is really cool -- to ask my next question: do you think it's possible to merge the two such that fibers are the underlying implementation structure for async/await, so we can preserve compatibility while using suck a fast implementation? I think the ecosystem bit is definitely worth considering. async/await have the benefit that we're able to do shenanigans in the background, even if it's only for, say, builtins. Compiling await fs.readFilePromise(...) to fs.readFileFiber() doesn't seem like a huge leap.

@ngot
Copy link

ngot commented Aug 26, 2017

Actually, it is already implemented in fibjs for a long time.

benchmark.js

const fs = require('fs');
const sync = require('util').sync;

const num = 100000;

let readFile = filename => {
  return new Promise((resolve, reject) => {
    fs.readFile(filename, (err, data) => {
      if (err) reject(err);
      else resolve(data);
    });
  });
};

readFile = sync(readFile, true);

console.time('async');
for (let i = 0; i < num; i++) {
  readFile(__filename);
}
console.timeEnd('async');

the result is:

➜ fibjs -v
v0.11.0
➜ fibjs benchmark.js
async: 7879.971ms

Another one

benchmark.js

const fs = require('fs');

const num = 100000;

const readFile = filename => {
  return new Promise((resolve, reject) => {
    fs.readFile(filename, (err, data) => {
      if (err) reject(err);
      else resolve(data);
    });
  });
};

(async () => {
  console.time('async');
  for (let i = 0; i < num; i++) {
    await readFile(__filename);
  }
  console.timeEnd('async');
})();

the result is:

➜ fibjs -v
v0.11.0
➜ fibjs benchmark.js
async: 3141.743ms

The performance of these two ways is bad because the promise is very slow.If you don't give up async/promise, there is no possibility to get high performance. The reason why fibjs is so fast is that our implementation of fiber is faster than libuv's callback mode.Besides, we also don't need async/promise which is very very slow.

@gunar
Copy link
Contributor

gunar commented Aug 27, 2017

It's not just about performance. Fibers allows for deep continuations a.k.a. true coroutines, something generator-based approach can never achieve.

@yuu2lee4 yuu2lee4 changed the title Bring fiber to ayo in core code? Bring true coroutines(fiber) to ayo in core code? Aug 27, 2017
@ljharb
Copy link

ljharb commented Aug 27, 2017

That's not a thing the JS language provides, though. Why should node provide it, as opposed to an actual language proposal?

@benjamingr
Copy link
Contributor

Actually, I want to be proven wrong here - and I want you to know you're being taken seriously here and your suggestions and feedback are welcome. Would you please:

If you have any questions in any of these stages please don't hesitate to ask and I promise to help. Then, once we have common ground with an experiment showing fibers are faster in a well known benchmark* we can discuss the performance implications with the V8 team and maybe experiment with fibers in core.

As @ljharb said, the process would still require a lot of work after fibers are shown to be faster (if they are) and discussion about the many implications. Even if fibers are significantly faster it still doesn't mean we can integrate them. Let's not get too far ahead of ourselves though.

* (so far they have been consistently shown them to be slower so far in our benchmarks - but I can see how integrating them into core gets a lot faster because - no closures - we got promises faster than callbacks at one point doing that).

@ngot
Copy link

ngot commented Aug 27, 2017

@benjamingr I'm afraid you still didn't get the point.

There are lots of work to do if you want to bring fiber into the core because the whole libuv needs to be rewritten, so I'm not requesting Node.js to implement the fiber mode.

I just want to point out that fiber is faster, here fiber is the lower-level concept than async/await. We've already implemented fiber in javascript in a project called fibjs, and according to the benchmark before, it shows the fiber is much faster than libuv. (14 times faster when qps is 100K)

@benjamingr
Copy link
Contributor

I ask that you moderate your comment above to use respectful language @ngot. If you would like to have meaningful and constructive discussion we're up for that.

@ngot
Copy link

ngot commented Aug 27, 2017

Sorry for that. My fault.

My point is :

  • Fiber is much fast.
  • Fiber vs Bluebird is confusing. They are not the same thing.
  • Fiber in JavaScript is already implemented.

IMO, it is worth to think twice about this issue.

@benjamingr
Copy link
Contributor

The link between fibers and bluebird (or promises) is that both techniques allow writing synchronous looking asynchronous code.

I realize the core underneath is different - that's why I asked that we have a well established benchmark as a point of discussion. In this case: doxbee which I linked to above.

We are not dismissing any of your suggestions and Ayo (and Node.js too by the way) is willing to listen and discuss

@ngot
Copy link

ngot commented Aug 27, 2017

Great.
Here is the key point: fiber should be compared with [libuv + bluebird]. I mean if we use fiber rewrites the whole architecture include libuv which will bring the high performance. If just use fiber as a replacement of promise, it just improves a little, maybe even worse which has been shown in the benchmark you mentioned above.

@Fishrock123
Copy link
Contributor

I would like to point out that there are almost certainly large ecosystem dependencies in npm in regards to certain parts of libuv behavior. Changing that for existing APIs may have widespread negative impact.

@yuu2lee4
Copy link
Author

yuu2lee4 commented Aug 28, 2017

So if you want merge back to node in the future or compatibal with node 100%(fibjs is 90% compatibal with node),maybe you should not implement fiber in ayo,but if not,you could try it or contribute code to fibjs directly.

@benjamingr
Copy link
Contributor

Let me reiterate. Ayo (and again, Node.js too) are open to working together and experimenting with this sort of things. If there is anything we can do from our side that you would need in order to participate in the project and try to promote these ideas please let us know.

I apologize if I sounded dismissive before and again - I would love to be proven wrong here. As @Fishrock123 said the barrier is going to be big because of possible ecosystem breakage - but I think that it's worth experimenting anyway.

@Fishrock123
Copy link
Contributor

Fishrock123 commented Aug 28, 2017

I agree it is worth experimenting with - unless I am radically misunderstanding what is involved however, it sounds like a native module would be a more ideal "proving grounds" for the work?

That is, what is the blocker or burden than makes core a necessary host for this initially?

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

10 participants