Tim, The I-Want-To-Abuse-Node-And-Calculate-Large-Primes-In-JavaScripts-Main-Thread denomination is a bit carricatural. I would rather call it:
I-Know-That-Node-Is-Single-Threaded-And-I-Want-My-Somewhat-Complex-Logic-To-Be-Well-Behaved-In-Node I would never compute large primes in the main thread. I would use threads-a-gogo for that. But I may have something which is not really computationally intensive but which may nevertheless use CPU slices that I'd like to break up. This is where I would use process.nextTick. The proposal of having a nextTick + a setImmediate sounds like a reasonable compromise, as long as setImmediate performs like the current nextTick. Bruno On Wednesday, May 30, 2012 12:02:09 AM UTC+2, Tim Caswell wrote: > > I understand that different people have different perspectives on the same > event. This is a common phenomenon. I've been working with node for a long > time. I started many months before it was announced to the world back in > 2009. When nextTick was introduced I remember it being for the purpose of > allowing my caller to register event handlers. To be able to execute code > after returning a value after run-to-completion finishes. setTimeout(fn, > 0) worked somewhat, but was slow and buggy since it introduced a lot of > race conditions that were hard to debug. > > During this conversation I have been surprised that a few people have > thought all along that nextTick's primary purpose was to break up CPU > intensive tasks and let real events seep in. > > Regardless of preconceived notions on the purpose of nextTick, these two > use cases are not compatible! The current implementation of nextTick is > about as good as a compromise between the two I can imagine. > > One use case requires that my callbacks get called after the current stack > runs to completion, but before and real events (I/O or timers). The > cpu-work-chunking use case requires that the callback not be allowed to > starve the real data events (It must allow real events in front of it). > > Here is the proposal as I see it > > The-Do-Work-After-Run-To-Completion case: > > process.nextTick(fn); > > fn will be appended to the current tick's nextTick queue. When the > current tick's stack unwinds and returns to the root, the queue will be > flushed. Any new nextTick calls during this flushing will be put at the > end of the queue. This way *all* nextTick functions will be called before > any other real event. > > I-Want-To-Abuse-Node-And-Calculate-Large-Primes-In-JavaScripts-Main-Thread > case: > > setImmediate(fn); > > fn will be appended to the end of the current event queue. Any data or io > events pending will be executed first. I'm still unclear on what happens > if real events happen while a setImmediate callback is still in queue. My > guess for now is that it's place is kept in the queue. > > On Tue, May 29, 2012 at 4:42 PM, Marco Rogers <marco.rog...@gmail.com>wrote: > >> Mikeal, I understand your frustration, but that's not how I read the >> history. nextTick was *intended* for this use case. But it sounds like it >> was the wrong solution. nextTick was implemented as "yield to the event >> loop for whatever else may happen". It's always been pretty clear to me >> that some early data events may get through this gap. The fact that you >> didn't actually want this doesn't mean there's a bug in nextTick. It means >> you screwed up. It means there's a bug in node because you took a valid >> nextTick implementation and used it for the wrong thing. It means you need >> another solution to solve your original problem. I thought that's why we >> started talking about setImmediate. >> >> As for whether it's valid to use nextTick or setTimeout or whatever to >> break up computation, that's not your call. People have been doing this in >> javascript for ages. Node can provide a "better" solution, but crippling >> current valid solutions is not really acceptable for a platform that claims >> to want to be simple and consistent and just javascript. IMO, >> cluster/child_process is for scaling request throughput for servers. It has >> little to do with breaking up computation though it can be used for that. >> This is not my impression, but one I got from you and Isaac and other node >> people when it was being designed. It feels like what's happening now, is >> that you're changing that tune so you can push this change forward. But >> whatever. >> >> You know if you're going to get upset when you receive honest, >> constructive feedback that you requested from actual users of your >> software, you should probably consider just not asking. >> >> :Marco >> >> >> On Tuesday, May 29, 2012 2:18:35 PM UTC-7, Mikeal Rogers wrote: >>> >>> The job of core is to provide the best API possible to accomplish >>> several use cases. >>> >>> When core provides an API to handle that use case and people decide to >>> ignore it, do something inferior with an API that was not designed for that >>> use case, and then protest altering the this API to better match the use >>> case it was actually intended for I don't have the words to describe how >>> frustrating it is. >>> >>> This is not a matter of "opinion". These APIs were created and >>> documented for a *purpose*. It's great when people find more than one >>> purpose for a given API but when their use case is actually covered by >>> another interface that was specifically designed to handle it we have to >>> ignore that input on the other API. >>> >>> The "change" we're talking about makes nextTick() behave the way most >>> people presume it works and for the use case it was designed for (adding >>> handlers after the current stack is complete but before IO gets processes) >>> the current behavior is a bug. The suggestion that we should let it remain >>> because the current behavior (which is broken for the desired use case) >>> fills another one it was not designed for and for which we have other >>> specifically designed API is ludicrous. >>> >>> -Mikeal >>> >>> On May 29, 2012, at May 29, 20122:08 PM, Marco Rogers wrote: >>> >>> Translation: "You're doing something reasonable. But we don't think you >>> should do it that way, so we're going to shoot you in the foot and then >>> blame you for it." I'm on board with this plan. <- sarcasm >>> >>> Seriously though. Can we at least hear what other options y'all have >>> considered for fixing the original problem? Is there a test case that >>> reproduces it that we can examine? I don't want to mess with nextTick >>> because it works as designed. But if there's no other solution to the >>> problem, I could get behind introducing setImmediate. But with that it >>> seems we're signing up for a whole new round of educating devs about what >>> to do in order to not miss their data events. Sure it seems easy in theory >>> (change nextTick to setImmediate), but in practice it will create a lot of >>> confusion and ambiguity about what just changed. >>> >>> :Marco >>> >>> PS - Sorry I missed the message about moving discussion to the github >>> ticket :-/ >>> >>> >>> On Tue, May 29, 2012 at 1:45 PM, Isaac Schlueter <i...@izs.me> wrote: >>> >>>> Computationally expensive stuff should be done in a child process, or >>>> a uv_work_t thread in an addon. nextTick is a bad fit for this. >>>> setTimeout(fn, 0) is not quite as bad, but it is slower. >>>> >>>> We can look into adding a setImmediate function for 0.9 that matches >>>> the semantics of the web browser. The intent of setImmediate is to be >>>> used for cases like this, and it should be pretty easy to implement. >>>> >>>> On Tue, May 29, 2012 at 1:31 PM, Mikeal Rogers <mikeal.rog...@gmail.com> >>>> wrote: >>>> > I have never seen nextTick recommended for breaking up computationally >>>> > expensive tasks, this is what cluster and child_process are for. >>>> > >>>> > Also, setTimeout(cb,0) is very efficient in node and does not suffer >>>> the >>>> > penalties we are familiar with from the browser. It's actually a >>>> better fit >>>> > for this use case than nextTick(). >>>> > >>>> > -Mikeal >>>> > >>>> > >>>> > On May 29, 2012, at May 29, 201212:23 PM, Bruno Jouhier wrote: >>>> > >>>> > +1 >>>> > >>>> > nextTick is the efficient way to yield to another "thread of >>>> processing" >>>> > (thread between quotes of course) when performing an expensive >>>> computation. >>>> > So it is the antidote to starvation and thus a very useful call. >>>> > >>>> > If you change its behavior, you should at least provide a replacement >>>> call >>>> > which will be at least as efficient (unlike setTimeout(cb, 0)). And >>>> then why >>>> > not keep nextTick as is and introduce another call with a different >>>> name >>>> > (like afterTick as someone suggested) if you really need one. >>>> > >>>> > >>>> > On Tuesday, May 29, 2012 2:43:20 AM UTC+2, phidelta wrote: >>>> >> >>>> >> I think that the current semantics have value. I use nextTick when I >>>> >> want to ensure that io can happen between the invocation and the >>>> >> ticked call. As well as to work with a new call stack. >>>> >> >>>> >> For example when I emit an event whose lister also emits an event and >>>> >> so on, I create a potentially long chain of stuff that can happen >>>> >> within a tick. So when I emit from within a listener I usually >>>> >> nextTick the emit to allow io in between. >>>> >> >>>> >> So if you change nextTick to really mean "at the end of this tick", >>>> at >>>> >> least we will want a function like reallyNextTick that keeps the >>>> >> current behavior. Of course I would need to do a search replace over >>>> a >>>> >> lot of code, but I could live with that. >>>> >> >>>> >> >>>> >> On May 26, 7:50 pm, Isaac Schlueter <i...@izs.me> wrote: >>>> >> > How would you feel about changing the semantics of process.nextTick >>>> >> > such that the nextTick queue is *always* cleared after every v8 >>>> >> > invocation, guaranteeing that a nextTick occurs before any IO can >>>> >> > happen? >>>> >> > >>>> >> > This would imply that you can starve the event loop by doing >>>> nextTick. >>>> >> > So, for example, the timeout would never fire in this code: >>>> >> > >>>> >> > setTimeout(function () { >>>> >> > console.log('timeout')}) >>>> >> > >>>> >> > process.nextTick(function f () { >>>> >> > process.nextTick(f) >>>> >> > >>>> >> > }) >>>> >> > >>>> >> > Reasoning: >>>> >> > >>>> >> > We have some cases in node where we use a nextTick to give the >>>> user a >>>> >> > chance to add event handlers before taking some action. However, >>>> >> > because we do not execute nextTick immediately (since that would >>>> >> > starve the event loop) you have very rare situations where IO can >>>> >> > happen in that window. >>>> >> > >>>> >> > Also, the steps that we go through to prevent nextTick starvation, >>>> and >>>> >> > yet try to always have nextTick be as fast as possible, results in >>>> >> > unnecessarily convoluted logic. >>>> >> > >>>> >> > This isn't going to change for v0.8, but if no one has a use-case >>>> >> > where it's known to break, we can try it early in v0.9. >>>> > >>>> > >>>> >>> >>> >>> >>> -- >>> Marco Rogers >>> marco.rog...@gmail.com | https://twitter.com/polotek >>> >>> Life is ten percent what happens to you and ninety percent how you >>> respond to it. >>> - Lou Holtz >>> >>> >>> >