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
>>>  
>>>
>>>
>

Reply via email to