ace icon indicating copy to clipboard operation
ace copied to clipboard

Comparison to connect/express?

Open jasonkuhrt opened this issue 11 years ago • 9 comments

@maccman I was wondering if you could offer some comparison to express. I asked TJ on IRC his thoughts:

kuhrt tjholowaychuk: do you have an opinion on Ace? https://github.com/maccman/ace
7:54 PM tjholowaychuk i wouldn't recommend it because of the node-fiber stack sizes
7:54 PM you would use a lot of memory
7:55 PM if we had growable stacks then yeah sure
7:55 PM kuhrt you don't mean this line do you?
7:55 PM "Node >= v0.7.3 is required, as well as npm. Ace will run on older versions of Node, but will crash under heavy load due to a bug in V8 (now fixed)."
7:55 PM tjholowaychuk no
7:56 PM kuhrt ok
7:56 PM tjholowaychuk just that stack sizes are pretty large
7:56 PM i forget the exact number
7:56 PM but basically you'd run out of memory fast if you had a lot of concurrent users
7:56 PM dylang has joined the channel.
7:56 PM tjholowaychuk well requests
7:56 PM kuhrt I thought the project looked somewhat ineteresting, fun to try maybe at least (what's different than express, concepts, etc.)
7:56 PM but the last commit was 5 months agoo
7:56 PM so it seems kind of dead
7:57 PM tjholowaychuk stack per request is great but not unless the entire community embraces coroutines
7:57 PM which has been killed off many times
7:57 PM in the mailing list etc
7:57 PM kuhrt hm
7:57 PM TimeTurner has left IRC ()
7:57 PM tjholowaychuk so basically it's between using lots of memory + sync or less memory + async
7:58 PM kuhrt ok
7:59 PM tjholowaychuk and obviously other things like ace's static file server being really poor but they could use "send" now
7:59 PM to get all the features that connect.static() provides under the hood
7:59 PM but yeah that's the fundamental tradeoff with multiple stacks unless you can grow like erlang
8:01 PM kuhrt tjholowaychuk: by "grow" you mean paralellize?
8:02 PM multi-core stuff
8:02 PM tjholowaychuk just grow like a 500 byte stack can grow to 1k or 5k if it needs more room
8:02 PM otherwise you're just wasting ram
8:03 PM kuhrt does your critique extend to strata or was that design choice at the Ace-level, or do you even know haha (talking to you like you're the author)
8:03 PM tjholowaychuk the default stack size for them is 64kb
8:03 PM so yeah, tons of memory
8:03 PM strata is the rack thing
8:03 PM kuhrt yup
8:03 PM tjholowaychuk more like connect
8:03 PM and ace is more like express
8:03 PM kuhrt yup
8:04 PM tjholowaychuk so for 1000 concurrency requests
8:04 PM kuhrt did you like anything in strata missing in connect?
8:04 PM tjholowaychuk you would use
8:04 PM 64mb of ram
8:04 PM on the stacks alone
8:04 PM vs 0
8:04 PM well vs node's single stack
8:05 PM which may or may not be a problem depending on the app

jasonkuhrt avatar Jul 12 '12 00:07 jasonkuhrt

Huh, that's a pretty fascinating conversation.

I think @visionmedia may be wrong though. node-fibers has a set amount of fibers, and makes sure it garbage collects old ones. Perhaps @laverdet could chime in.

maccman avatar Jul 12 '12 02:07 maccman

I saw some pooling thing in the source but I didn't look at that part too close not sure what that's for, but in general if you have N concurrent requests you would have N of these light-weight threads, just a tradeoff in this case since they dont grow, otherwise I'd advocate threads over callbacks any day

tj avatar Jul 12 '12 02:07 tj

plus there's also the adoption problem in node since everyone uses callbacks

tj avatar Jul 12 '12 02:07 tj

Yes, that conversation seems about accurate, depending on how you're using fibers (I have not personally looked at the source code for Ace).

It is true to say that for every Fiber that is currently in a yielding state, you will be using 64kb of memory.

For this reason using Fibers is a fairly poor choice for long poll applications with many concurrent users. Fortunately, however, usually long poll applications will have a only a few points where you are waiting for an event to return the poll. This critical section should be written with a callback, which gives you the luxury of using Fibers throughout your application. Generally it would be advised to only use a Fiber while you are waiting for some kind of io event that should come back in some reasonable amount of time. url requests, db requests, file io, child processes, these could all be written with Fibers with relatively little overhead (if you have 1000 pending io operations, 64mb of memory is likely the least of your concerns).

laverdet avatar Jul 12 '12 05:07 laverdet

@maccman so how does Ace fare in the patterns @laverdet mentions? Say for a standard brochure site or fancy micro site ?

jasonkuhrt avatar Jul 13 '12 23:07 jasonkuhrt

@jasonkuhrt you wont have any problems at all in cases like that. I think the biggest problem facing node as far as coroutines go is a) start with small growable stacks, b) the community has largely dismissed them, usually without reasoning which is somewhat frustrating. From a community aspect it would be difficult to use them I think, since it kinda fragments the concurrency model which was really the best part about node, one concurrency model. Wrapping third-party libraries to have nice fiber-friendly APIs would be a pain I think

tj avatar Jul 14 '12 19:07 tj

@visionmedia Although it's worth noting ace extends EventEmitter and Function, so most async libs are fiber ready.

maccman avatar Jul 14 '12 20:07 maccman

ah I see, the .wait() stuff. That's definitely better than callbacks, but ideally if a community was built ground-up with coros as "the" concurrency model we'd just have nice fs.read(file) => Buffer etc vs fs.read(file).wait()

tj avatar Jul 14 '12 21:07 tj

Another thing that's important to mention is that even though node-fibers will allocate 64kb for each fiber, most operating systems will only actually commit memory as you write to it in 4kb page sizes. So if you are just building a bunch of short-lived fibers you'll only be using 4kb or 8kb per fiber.

The issue of community support is definitely an issue, but I don't really think that should affect many users of fibers. For one, node-fibers has 500+ followers on github, so there is definitely substantial interest. Secondly, it's pretty simple to build very robust adapters between callbacks and fibers which eases working with fiber and non-fiber code.

Re: wait() I'm not sure we'd end up with a wait-less implementation if Node was built from scratch with coroutines in mind. What you're describing seems closer to something that Lisp might do, but I'm not really sure the technology exists in Javascript to do that effectively. With ES5 Proxy objects this may be a possibility, but explicit yield points seem valuable. The biggest issue to me is that when you're using 3rd party libraries you generally want to wrap their interfaces with future-returning versions. I'm not sure how Ace does it, but with fibers/future you can just do var read = Future.wrap(require('fs').read) to turn a standard callback-based function into one that returns a future instead.

laverdet avatar Jul 15 '12 07:07 laverdet