I don’t understand why you’d want to use process.nextTick() for that, or 
indeed, any similar API. The API you want is “do this work in a separate 
thread/process/other schedulable unit that the operating system knows about”.

From: nodejs-dev@googlegroups.com [mailto:nodejs-dev@googlegroups.com] On 
Behalf Of Bruno Jouhier
Sent: 29 May 2012 23:21
To: nodejs-dev@googlegroups.com
Subject: Re: [node-dev] Re: process.nextTick semantics

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