The git issue now has good examples of why something higher-priority and something lower-priority than the current nextTick compromise are desired. As long as not just the higher-priority one is provided, I'll be happy.
On Wednesday, 30 May 2012 15:33:20 UTC+1, Tim Caswell wrote:
> On Wed, May 30, 2012 at 4:12 AM, James Howe <ja...@howeswho.co.uk> wrote:
>> Sorry if I'm being obtuse, but why do you need a special API for >> Do-Work-After-Run-To-Completion? Can that not be achieved just with normal >> program flow-control (i.e. do the work, do the thing after the work, >> return)?
> No. It's impossible to do anything after returning using normal > control-flow. A perfect example is a function that returns an event > emitter. The code that attaches event listeners to the emitter *can't* > attach listeners till you return the emitter. But there are times that you > want to emit events as soon as possible. nextTick tells node to call your > function after your caller returns and the whole stack unwinds.
>> Further to my assumptions (and experience) about what nextTick does, it >> seemed obvious to me that you need to set the handlers before you returned >> from the stack to avoid missing data events. Setting them before returning >> doesn't cause any problems, as those events can't be processed until you've >> returned anyway.
>> And to Mikeal, I have quite sizeable projects that would go wrong if >> nextTick semantics are changed (and we don't find some way to fix them) but >> haven't posted examples because they are a) sizeable, b) closed-source and >> c) I don't have time.
> Are you cases where you depend on the current implementation of nextTick > easy to work around? I know I have tons of code that depends on the > current behavior, but in every case I could modify my code to not depend on > the behavior.
> Everyone, please read the thread in the gist that Isaac posted. There are > several proposed new APIs that make it possible to do low-priority work > that doesn't starve/block the event loop.
>> Regards
>> On Wednesday, 30 May 2012 04:21:58 UTC+1, CrabDude wrote:
>>> There seem to be 2 considerations:
>>> 1. Adding sameTick() functionality to node. >>> 2. Whether nextTick() should house that behavior, or another API / name.
>>> FWIW, I always misunderstood process.nextTick() to occur, as the name >>> implies, at the beginning of the next tick. In other words, the name >>> implied to me that it would yield to any queued timer / IO events, and then >>> execute at the beginning of the next event loop. In fact, b/c of this >>> misunderstanding, I found nextTick() and setImmediate() to be eventually >>> redundant.
>>> I feel fairly confident in saying that it would be easier for core to >>> implement the desired behavior under a different name (sameTick(), etc...) >>> and replace all calls to nextTick() with sameTick(), thisTick(), etc..., >>> than to change the misperceptions others may have regarding what the >>> function name implies, that it in fact actually does not execute until the >>> _next_ tick. Changing the behavior of nextTick to something that conflicts >>> with its name, would seem to inevitably cause misunderstandings. Core >>> obviously (from this thread) though has a different perception of the >>> purpose of nextTick, since it seems it has a very specific purpose for >>> which it was created and is used. Ironically, those most familiar with its >>> *intended purpose* are also those that are most aware that its >>> implementation is not always consistent with that purpose.
>>> Is there any reasoning core has regarding why replacing all nextTick() >>> calls with thisTick() would be problematic? It is after all new >>> functionality, and once again the name nextTick() seems inconsistent with >>> its proposed new implementation.
>>> Wouldn't nextTick inevitably be deprecated / replaced by setImmediate >>> anyways? It's too bad too, nexTick() is a great name, much nicer than >>> "sameTick," "thisTick," etc...
>>> Cheers, >>> Adam Crabtree
>>> On Tue, May 29, 2012 at 4:28 PM, Marco Rogers wrote:
>>>>> The problem with this characterization of the API's history is that >>>>> it's actually not distinguishable from setTimeout(fn, 0) except in >>>>> implementation. As described, they are for quite literally the same thing >>>>> although one of them is a little better at it because of an implementation >>>>> detail. If this characterization is true (i don't believe it is) then we >>>>> should re-purpose or remove nextTick() and improve the performance of >>>>> setTimeout(fn,0). I'm not suggesting that is what we do, but it's the >>>>> logical conclusion to this characterization.
>>>> This characterization comes from people's real impressions of nextTick. >>>> If you want to change that impression, you have some work to do.
>>>>> As for whether it's valid to use nextTick or setTimeout or whatever to >>>>> break up computation, that's not your call.
>>>>> Are you saying that core can't state the intention of an API? That's >>>>> insane.
>>>>> Core is free to change the implementation details and semantics of an >>>>> API at any time, and has on many occasions. This is always done with the >>>>> intention of making it *better*. In order to characterize what is "better" >>>>> the API must have a purpose and that has always been dictated by core (Ryan >>>>> and then Isaac).
>>>> As for the purpose of nextTick, I did agree on what the intended >>>> purpose was. And yes you can change whatever you want. You guys are in >>>> charge. And we're free to tell you it was a bad idea. You're free to get >>>> mad about that. And we're free to tell you you're being kind of bratty >>>> about it. Everybody's free! The only problem here is that you think you're >>>> allowed to think you're right more than we're allowed to think you're >>>> wrong. Strange isn't it?
>>>> Let me be clear. I think the problem with missing data events should be >>>> fixed. But we should evaluate the solutions to make sure they aren't going >>>> to cause follow on problems that will haunt us. That's what I'm doing here. >>>> If you don't agree about follow on problems, say that. If you don't want to >>>> discuss potential follow on problems, say that. If you want to be upset >>>> that not everybody who uses node has the exact same view of it's >>>> affordances as you do... well I don't know how to help you with that.
>>>>> Instead, we got a lot of comments about names and about theoretical >>>>> breakage in code without anyone noting running code that actually breaks or >>>>> is even valid. And now we're being taken down the rabbit hole of "I can't >>>>> use this for something it wasn't designed for".
>>>> So since a hand full of people who saw this message and decided to >>>> respond don't have concrete use cases in hand ready to go, you can dismiss >>>> all concerns? That's crap. We *should* find some use cases, but that >>>> doesn't mean the discussion here isn't useful or that we can't reason about >>>> what might happen. Reasoning about semantics is how programming works. Or >>>> at least that's usually how I do it.
>>>> The way in which people are providing feedback to this proposed changed >>>>> is unproductive because they do not recognize the reality of the current >>>>> semantics. >>>>> 1) that we cannot remove nextTick() and it is heavily relied on. >>>>> 2) that much of the code that *currently* relies on nextTick() breaks >>>>> under heavy load because of the current implementation.
>>>>> All of this feedback is "me too". It's statements of opinion without >>>>> reference the problem that must be solved.
>>>> There's some truth to this. As I said, the problem to be solved is >>>> important. But pretending it's the only thing that's important and that >>>> there isn't potential to cause other problems is ludicrous. Also ludicrous >>>> is bullying and yelling at people who came here to discuss things with you >>>> in good faith precisely because we care deeply about node and the direction >>>> it goes in. Try to get some perspective here man. Also try meditation.
>>>>> The intention of feedback should be to change the minds of those that >>>>> proposed the change, not to prove that your'e right under your terms.
>>>> I don't think that's what anyone here has done. I even started out by >>>> saying I may need to be educated about this. But I also think you and other >>>> core guys are sometimes obtuse and dismissive about how non-core people >>>> actually build their mental model about node execution and how that affects >>>> the solutions they come up with. I'm not giving you *my* terms. I'm giving >>>> you the terms I've gotten from talking to a lot of people who are not node >>>> experts. And as much as node benefits from not having the baggage of >>>> traditional notions of i/o, it does have the baggage of people's long >>>> experience with javascript execution. You can ignore that useful data at >>>> your peril.
>>>> :Marco
>>>> -- >>>> Marco Rogers
>>>> Life is ten percent what happens to you and ninety percent how you >>>> respond to it. >>>> - Lou Holtz
>>> -- >>> Better a little with righteousness >>> than much gain with injustice. >>> Proverbs 16:8
>> On Wednesday, 30 May 2012 04:21:58 UTC+1, CrabDude wrote:
>>> There seem to be 2 considerations:
>>> 1. Adding sameTick() functionality to node. >>> 2. Whether nextTick() should house that behavior, or another API / name.
>>> FWIW, I always misunderstood process.nextTick() to occur, as the name >>> implies, at the beginning of the next tick. In other words, the name >>> implied to me that it
If there are bugs in node's internal libraries/code due to nextTick()'s current behaviour, they can simply rewrite nextTick() as they please into a *new* method with a *different* name such as e.g. thisTick, and do an s/nextTick/thisTick/g onto node's source code and that's it.
But there's no need to touch (such an essential piece of) node's public API (and fuck all its users and their programs) to fix node's internal bugs.
-- Jorge.
> The git issue now has good examples of why something higher-priority and something lower-priority than the current nextTick compromise are desired.
> As long as not just the higher-priority one is provided, I'll be happy.
> On Wednesday, 30 May 2012 15:33:20 UTC+1, Tim Caswell wrote:
> On Wed, May 30, 2012 at 4:12 AM, James Howe <ja...@howeswho.co.uk> wrote:
> Sorry if I'm being obtuse, but why do you need a special API for Do-Work-After-Run-To-Completion? Can that not be achieved just with normal program flow-control (i.e. do the work, do the thing after the work, return)?
> No. It's impossible to do anything after returning using normal control-flow. A perfect example is a function that returns an event emitter. The code that attaches event listeners to the emitter *can't* attach listeners till you return the emitter. But there are times that you want to emit events as soon as possible. nextTick tells node to call your function after your caller returns and the whole stack unwinds.
> Further to my assumptions (and experience) about what nextTick does, it seemed obvious to me that you need to set the handlers before you returned from the stack to avoid missing data events. Setting them before returning doesn't cause any problems, as those events can't be processed until you've returned anyway.
> And to Mikeal, I have quite sizeable projects that would go wrong if nextTick semantics are changed (and we don't find some way to fix them) but haven't posted examples because they are a) sizeable, b) closed-source and c) I don't have time.
> Are you cases where you depend on the current implementation of nextTick easy to work around? I know I have tons of code that depends on the current behavior, but in every case I could modify my code to not depend on the behavior.
> Everyone, please read the thread in the gist that Isaac posted. There are several proposed new APIs that make it possible to do low-priority work that doesn't starve/block the event loop.
> Regards
> On Wednesday, 30 May 2012 04:21:58 UTC+1, CrabDude wrote:
> There seem to be 2 considerations:
> 1. Adding sameTick() functionality to node.
> 2. Whether nextTick() should house that behavior, or another API / name.
> FWIW, I always misunderstood process.nextTick() to occur, as the name implies, at the beginning of the next tick. In other words, the name implied to me that it would yield to any queued timer / IO events, and then execute at the beginning of the next event loop. In fact, b/c of this misunderstanding, I found nextTick() and setImmediate() to be eventually redundant.
> I feel fairly confident in saying that it would be easier for core to implement the desired behavior under a different name (sameTick(), etc...) and replace all calls to nextTick() with sameTick(), thisTick(), etc..., than to change the misperceptions others may have regarding what the function name implies, that it in fact actually does not execute until the _next_ tick. Changing the behavior of nextTick to something that conflicts with its name, would seem to inevitably cause misunderstandings. Core obviously (from this thread) though has a different perception of the purpose of nextTick, since it seems it has a very specific purpose for which it was created and is used. Ironically, those most familiar with its *intended purpose* are also those that are most aware that its implementation is not always consistent with that purpose.
> Is there any reasoning core has regarding why replacing all nextTick() calls with thisTick() would be problematic? It is after all new functionality, and once again the name nextTick() seems inconsistent with its proposed new implementation.
> Wouldn't nextTick inevitably be deprecated / replaced by setImmediate anyways? It's too bad too, nexTick() is a great name, much nicer than "sameTick," "thisTick," etc...
> Cheers,
> Adam Crabtree
> On Tue, May 29, 2012 at 4:28 PM, Marco Rogers wrote:
> The problem with this characterization of the API's history is that it's actually not distinguishable from setTimeout(fn, 0) except in implementation. As described, they are for quite literally the same thing although one of them is a little better at it because of an implementation detail. If this characterization is true (i don't believe it is) then we should re-purpose or remove nextTick() and improve the performance of setTimeout(fn,0). I'm not suggesting that is what we do, but it's the logical conclusion to this characterization.
> This characterization comes from people's real impressions of nextTick. If you want to change that impression, you have some work to do.
>> As for whether it's valid to use nextTick or setTimeout or whatever to break up computation, that's not your call.
> Are you saying that core can't state the intention of an API? That's insane.
> Core is free to change the implementation details and semantics of an API at any time, and has on many occasions. This is always done with the intention of making it *better*. In order to characterize what is "better" the API must have a purpose and that has always been dictated by core (Ryan and then Isaac).
> As for the purpose of nextTick, I did agree on what the intended purpose was. And yes you can change whatever you want. You guys are in charge. And we're free to tell you it was a bad idea. You're free to get mad about that. And we're free to tell you you're being kind of bratty about it. Everybody's free! The only problem here is that you think you're allowed to think you're right more than we're allowed to think you're wrong. Strange isn't it?
> Let me be clear. I think the problem with missing data events should be fixed. But we should evaluate the solutions to make sure they aren't going to cause follow on problems that will haunt us. That's what I'm doing here. If you don't agree about follow on problems, say that. If you don't want to discuss potential follow on problems, say that. If you want to be upset that not everybody who uses node has the exact same view of it's affordances as you do... well I don't know how to help you with that.
> Instead, we got a lot of comments about names and about theoretical breakage in code without anyone noting running code that actually breaks or is even valid. And now we're being taken down the rabbit hole of "I can't use this for something it wasn't designed for".
> So since a hand full of people who saw this message and decided to respond don't have concrete use cases in hand ready to go, you can dismiss all concerns? That's crap. We *should* find some use cases, but that doesn't mean the discussion here isn't useful or that we can't reason about what might happen. Reasoning about semantics is how programming works. Or at least that's usually how I do it.
> The way in which people are providing feedback to this proposed changed is unproductive because they do not recognize the reality of the current semantics.
> 1) that we cannot remove nextTick() and it is heavily relied on.
> 2) that much of the code that *currently* relies on nextTick() breaks under heavy load because of the current implementation.
> All of this feedback is "me too". It's statements of opinion without reference the problem that must be solved.
> There's some truth to this. As I said, the problem to be solved is important. But pretending it's the only thing that's important and that there isn't potential to cause other problems is ludicrous. Also ludicrous is bullying and yelling at people who came here to discuss things with you in good faith precisely because we care deeply about node and the direction it goes in. Try to get some perspective here man. Also try meditation.
> The intention of feedback should be to change the minds of those that proposed the change, not to prove that your'e right under your terms.
> I don't think that's what anyone here has done. I even started out by saying I may need to be educated about this. But I also think you and other core guys are sometimes obtuse and dismissive about how non-core people actually build their mental model about node execution and how that affects the solutions they come up with. I'm not giving you *my* terms. I'm giving you the terms I've gotten from talking to a lot of people who are not node experts. And as much as node benefits from not having the baggage of traditional notions of i/o, it does have the baggage of people's long experience with javascript execution. You can ignore that useful data at your peril.
> :Marco
> -- > Marco Rogers
> Life is ten percent what happens to you and ninety percent how you respond to it.
> - Lou Holtz
> -- > Better a little with righteousness > than much gain with injustice.
> Proverbs 16:8
> On Wednesday, 30 May 2012 04:21:58 UTC+1, CrabDude wrote:
> There seem to be 2 considerations:
> 1. Adding sameTick() functionality to node.
> 2. Whether nextTick() should house that behavior, or another API / name.
> FWIW, I always misunderstood process.nextTick() to occur, as the name implies, at the beginning of the next tick. In other words, the name implied to me that it would yield to any queued timer / IO events, and then execute at the beginning of the next event loop. In fact, b/c of this misunderstanding, I found nextTick() and
Stop arguing. Let's have them all. They all have different semantic
values that are handy.
Old guys:
setTimeout === I don't care when these will happen, just that they
will happen eventually, sometime later. I don't care about their
order. I also want to keep a reference, in case I want to cancel them.
nextTick === I want the stuff I call to run first on the next tick, in
the order I called them. I'm never gonna need to cancel these.
New guys:
setImmediate === Similar to nextTick but with a reference, so I may
cancel it during this tick, or within an afterTick/nextTick call.
afterTick === Before jumping to the next tick, and after this tick has
ran to completion, run these in order.
In perspective:
tick...nextTick stuff...setImmediate stuff...everything else I don't
care about their order, setTimeouts, events etc...afterTick
stuff...tick.....
> If there are bugs in node's internal libraries/code due to nextTick()'s current behaviour, they can simply rewrite nextTick() as they please into a *new* method with a *different* name such as e.g. thisTick, and do an s/nextTick/thisTick/g onto node's source code and that's it.
> But there's no need to touch (such an essential piece of) node's public API (and fuck all its users and their programs) to fix node's internal bugs.
> --
> Jorge.
> On May 31, 2012, at 10:50 AM, James Howe wrote:
>> The git issue now has good examples of why something higher-priority and something lower-priority than the current nextTick compromise are desired.
>> As long as not just the higher-priority one is provided, I'll be happy.
>> On Wednesday, 30 May 2012 15:33:20 UTC+1, Tim Caswell wrote:
>> On Wed, May 30, 2012 at 4:12 AM, James Howe <ja...@howeswho.co.uk> wrote:
>> Sorry if I'm being obtuse, but why do you need a special API for Do-Work-After-Run-To-Completion? Can that not be achieved just with normal program flow-control (i.e. do the work, do the thing after the work, return)?
>> No. It's impossible to do anything after returning using normal control-flow. A perfect example is a function that returns an event emitter. The code that attaches event listeners to the emitter *can't* attach listeners till you return the emitter. But there are times that you want to emit events as soon as possible. nextTick tells node to call your function after your caller returns and the whole stack unwinds.
>> Further to my assumptions (and experience) about what nextTick does, it seemed obvious to me that you need to set the handlers before you returned from the stack to avoid missing data events. Setting them before returning doesn't cause any problems, as those events can't be processed until you've returned anyway.
>> And to Mikeal, I have quite sizeable projects that would go wrong if nextTick semantics are changed (and we don't find some way to fix them) but haven't posted examples because they are a) sizeable, b) closed-source and c) I don't have time.
>> Are you cases where you depend on the current implementation of nextTick easy to work around? I know I have tons of code that depends on the current behavior, but in every case I could modify my code to not depend on the behavior.
>> Everyone, please read the thread in the gist that Isaac posted. There are several proposed new APIs that make it possible to do low-priority work that doesn't starve/block the event loop.
>> Regards
>> On Wednesday, 30 May 2012 04:21:58 UTC+1, CrabDude wrote:
>> There seem to be 2 considerations:
>> 1. Adding sameTick() functionality to node.
>> 2. Whether nextTick() should house that behavior, or another API / name.
>> FWIW, I always misunderstood process.nextTick() to occur, as the name implies, at the beginning of the next tick. In other words, the name implied to me that it would yield to any queued timer / IO events, and then execute at the beginning of the next event loop. In fact, b/c of this misunderstanding, I found nextTick() and setImmediate() to be eventually redundant.
>> I feel fairly confident in saying that it would be easier for core to implement the desired behavior under a different name (sameTick(), etc...) and replace all calls to nextTick() with sameTick(), thisTick(), etc..., than to change the misperceptions others may have regarding what the function name implies, that it in fact actually does not execute until the _next_ tick. Changing the behavior of nextTick to something that conflicts with its name, would seem to inevitably cause misunderstandings. Core obviously (from this thread) though has a different perception of the purpose of nextTick, since it seems it has a very specific purpose for which it was created and is used. Ironically, those most familiar with its *intended purpose* are also those that are most aware that its implementation is not always consistent with that purpose.
>> Is there any reasoning core has regarding why replacing all nextTick() calls with thisTick() would be problematic? It is after all new functionality, and once again the name nextTick() seems inconsistent with its proposed new implementation.
>> Wouldn't nextTick inevitably be deprecated / replaced by setImmediate anyways? It's too bad too, nexTick() is a great name, much nicer than "sameTick," "thisTick," etc...
>> Cheers,
>> Adam Crabtree
>> On Tue, May 29, 2012 at 4:28 PM, Marco Rogers wrote:
>> The problem with this characterization of the API's history is that it's actually not distinguishable from setTimeout(fn, 0) except in implementation. As described, they are for quite literally the same thing although one of them is a little better at it because of an implementation detail. If this characterization is true (i don't believe it is) then we should re-purpose or remove nextTick() and improve the performance of setTimeout(fn,0). I'm not suggesting that is what we do, but it's the logical conclusion to this characterization.
>> This characterization comes from people's real impressions of nextTick. If you want to change that impression, you have some work to do.
>>> As for whether it's valid to use nextTick or setTimeout or whatever to break up computation, that's not your call.
>> Are you saying that core can't state the intention of an API? That's insane.
>> Core is free to change the implementation details and semantics of an API at any time, and has on many occasions. This is always done with the intention of making it *better*. In order to characterize what is "better" the API must have a purpose and that has always been dictated by core (Ryan and then Isaac).
>> As for the purpose of nextTick, I did agree on what the intended purpose was. And yes you can change whatever you want. You guys are in charge. And we're free to tell you it was a bad idea. You're free to get mad about that. And we're free to tell you you're being kind of bratty about it. Everybody's free! The only problem here is that you think you're allowed to think you're right more than we're allowed to think you're wrong. Strange isn't it?
>> Let me be clear. I think the problem with missing data events should be fixed. But we should evaluate the solutions to make sure they aren't going to cause follow on problems that will haunt us. That's what I'm doing here. If you don't agree about follow on problems, say that. If you don't want to discuss potential follow on problems, say that. If you want to be upset that not everybody who uses node has the exact same view of it's affordances as you do... well I don't know how to help you with that.
>> Instead, we got a lot of comments about names and about theoretical breakage in code without anyone noting running code that actually breaks or is even valid. And now we're being taken down the rabbit hole of "I can't use this for something it wasn't designed for".
>> So since a hand full of people who saw this message and decided to respond don't have concrete use cases in hand ready to go, you can dismiss all concerns? That's crap. We *should* find some use cases, but that doesn't mean the discussion here isn't useful or that we can't reason about what might happen. Reasoning about semantics is how programming works. Or at least that's usually how I do it.
>> The way in which people are providing feedback to this proposed changed is unproductive because they do not recognize the reality of the current semantics.
>> 1) that we cannot remove nextTick() and it is heavily relied on.
>> 2) that much of the code that *currently* relies on nextTick() breaks under heavy load because of the current implementation.
>> All of this feedback is "me too". It's statements of opinion without reference the problem that must be solved.
>> There's some truth to this. As I said, the problem to be solved is important. But pretending it's the only thing that's important and that there isn't potential to cause other problems is ludicrous. Also ludicrous is bullying and yelling at people who came here to discuss things with you in good faith precisely because we care deeply about node and the direction it goes in. Try to get some perspective here man. Also try meditation.
>> The intention of feedback should be to change the minds of those that proposed the change, not to prove that your'e right under your terms.
>> I don't think that's what anyone here has done. I even started out by saying I may need to be educated about this. But I also think you and other core guys are sometimes obtuse and dismissive about how non-core people actually build their mental model about node execution and how that affects the solutions they come up with. I'm not giving you *my* terms. I'm giving you the terms I've gotten from talking to a lot of people who are not node experts. And as much as node benefits from not having the
The problem is that the current nextTick semantics are terrible. We
cannot keep it as it is forever.
The use cases provided in opposition to this change are very bad
ideas. In all of the cases presented, what you actually want is
either a separate thread of execution or an idle listener; *not* a
maximum-priority scheduled task in the current thread. People
sometimes use setTimeout(fn,0) in the browser for CPU-intensive
operations, **because there is no other choice**, but even in those
cases, it's better to use WebWorkers instead, now that they are pretty
widely supported.
The bugs we're seeing in node-core are not just in node-core. Any
library that uses nextTick for its *intended purpose*, to defer
execution until after the current run-to-completion, but before
normal-priority IO events have a chance to fire, will find that they
have the same sporadic bugs at scale.
No kittens will die from this change. What will happen is that a few
terrible abuses of nextTick will perhaps behave slightly more badly.
And even there, we could probably set it up so that nextTicks added in
the nextTick phase are deferred until later. No one's dug into the
code to try and do this, and it's not scheduled until after 0.8
anyway, so it's all vaporware at this point.
The real source of this problem is that the concept of a "tick" is
pretty loosely defined in Node, and not very well understood. As a
result, a lot of people have come up with their own (mostly wrong)
beliefs about how it works, and have built libraries around those
beliefs. The semantics are too complicated to get right all the time,
and we're seeing the results of that.
You can't please everyone. We're going to fix node so that it's
better at its primary focus. If you're using nextTick for
CPU-intensive operations, it's already terrible, and it's going to get
worse, so stop that; use a child process. If you're using it as an
idle-listener, it's not that, so stop; setTimeout is better (since
it's lower priority and abuses the CPU less badly).
Adding setImmediate is not out of the question, but is far from
decided. We're not going to keep the current terrible complicated
only-fails-in-production nextTick semantics, and then further confuse
things by adding an "afterTick" that actually works.
The use cases provided in opposition to this change are very bad
> ideas. In all of the cases presented, what you actually want is
> either a separate thread of execution or an idle listener; *not* a
> maximum-priority scheduled task in the current thread. People
> sometimes use setTimeout(fn,0) in the browser for CPU-intensive
> operations, **because there is no other choice**, but even in those
> cases, it's better to use WebWorkers instead, now that they are pretty
> widely supported.
I think this is too simplistic a view. The issue isn't that people are
doing compute-intensive tasks like calculating fibonacci numbers; they are
processing application state, which involve collections of indefinite size,
and this state is necessarily in the current isolate. The work can't be
offloaded into a child process. There is a legitimate need, IMO, to be able
to perform some processing on those indefinitely-size collections without
stalling the event loop for an indefinite time - even if that time is
"only" an unbounded number of microseconds, so to speak. This requires some
way of scheduling some work to be done, after completion of the current
work, without preempting the handling of (IO and other) events that have
occurred during the processing of the current work.
The bugs we're seeing in node-core are not just in node-core. Any
> library that uses nextTick for its *intended purpose*, to defer
> execution until after the current run-to-completion, but before
> normal-priority IO events have a chance to fire, will find that they
> have the same sporadic bugs at scale.
This is clearly a fatal problem that needs to be fixed.
> The real source of this problem is that the concept of a "tick" is
> pretty loosely defined in Node, and not very well understood. As a
> result, a lot of people have come up with their own (mostly wrong)
> beliefs about how it works, and have built libraries around those
> beliefs. The semantics are too complicated to get right all the time,
> and we're seeing the results of that.
Quite. Of all of the unfortunate things about nextTick, the name is the
most unfortunate. The word 'tick' implies that there is some periodic time
interval, and nextTick defers things until that time interval has elapsed.
Anyone sensible encountering it for the first time will surely know that it
would be insane for things to work that way, so he must then conclude that
he has no clue about what it *actually* does; and as we know the docs don't
help.
If we had a clean sheet of paper - which we don't, of course - then none of
the APIs would have the word 'tick' in them because it can only be
misleading.
So, it seems to me we do need:
a) "process_before_already_scheduled_events" - to address the main
use-case, which is Isaac's proposed behaviour for nextTick;
b) "schedule_after_already_scheduled_events" - to address the use case of
being able to schedule work in parcels that would otherwise preempt event
processing for unbounded time.
(a) is a critical need, and the "official" purpose of nextTick, so its
current behaviour is broken and it needs fixing to behave this way. There
is an option to introduce a new more meaningful name and deprecate
nextTick; but even then nextTick is obviously never going to go away, so it
just needs to be very carefully documented and the name explained as an
unfortunate artifact of history.
(b) I believe is a genuine need and hopefully we can think of a good name
for it, and implement it.
On May 31, 2012, at May 31, 20121:05 PM, Paddy Byers wrote:
> Hi,
> Here's my input, FWIW:
> The use cases provided in opposition to this change are very bad
> ideas. In all of the cases presented, what you actually want is
> either a separate thread of execution or an idle listener; *not* a
> maximum-priority scheduled task in the current thread. People
> sometimes use setTimeout(fn,0) in the browser for CPU-intensive
> operations, **because there is no other choice**, but even in those
> cases, it's better to use WebWorkers instead, now that they are pretty
> widely supported.
> I think this is too simplistic a view. The issue isn't that people are doing compute-intensive tasks like calculating fibonacci numbers; they are processing application state, which involve collections of indefinite size, and this state is necessarily in the current isolate. The work can't be offloaded into a child process. There is a legitimate need, IMO, to be able to perform some processing on those indefinitely-size collections without stalling the event loop for an indefinite time - even if that time is "only" an unbounded number of microseconds, so to speak. This requires some way of scheduling some work to be done, after completion of the current work, without preempting the handling of (IO and other) events that have occurred during the processing of the current work.
Neither approach is correct.
If a collection is of "indefinite size" then it should not be loaded entirely in to memory in order to accomplish computation, it should be streamed. In the case of streaming the collection you can iteratively perform the computation without locking up the process indefinitely and without taking on a large memory footprint of either the original collection or even what has already been processed.
> The bugs we're seeing in node-core are not just in node-core. Any
> library that uses nextTick for its *intended purpose*, to defer
> execution until after the current run-to-completion, but before
> normal-priority IO events have a chance to fire, will find that they
> have the same sporadic bugs at scale.
> This is clearly a fatal problem that needs to be fixed.
> The real source of this problem is that the concept of a "tick" is
> pretty loosely defined in Node, and not very well understood. As a
> result, a lot of people have come up with their own (mostly wrong)
> beliefs about how it works, and have built libraries around those
> beliefs. The semantics are too complicated to get right all the time,
> and we're seeing the results of that.
> Quite. Of all of the unfortunate things about nextTick, the name is the most unfortunate. The word 'tick' implies that there is some periodic time interval, and nextTick defers things until that time interval has elapsed. Anyone sensible encountering it for the first time will surely know that it would be insane for things to work that way, so he must then conclude that he has no clue about what it *actually* does; and as we know the docs don't help.
> If we had a clean sheet of paper - which we don't, of course - then none of the APIs would have the word 'tick' in them because it can only be misleading.
> So, it seems to me we do need:
> a) "process_before_already_scheduled_events" - to address the main use-case, which is Isaac's proposed behaviour for nextTick;
> b) "schedule_after_already_scheduled_events" - to address the use case of being able to schedule work in parcels that would otherwise preempt event processing for unbounded time.
> (a) is a critical need, and the "official" purpose of nextTick, so its current behaviour is broken and it needs fixing to behave this way. There is an option to introduce a new more meaningful name and deprecate nextTick; but even then nextTick is obviously never going to go away, so it just needs to be very carefully documented and the name explained as an unfortunate artifact of history.
> (b) I believe is a genuine need and hopefully we can think of a good name for it, and implement it.
If a collection is of "indefinite size" then it should not be loaded
> entirely in to memory in order to accomplish computation, it should be
> streamed. In the case of streaming the collection you can iteratively
> perform the computation without locking up the process indefinitely and
> without taking on a large memory footprint of either the original
> collection or even what has already been processed.
Yes, you stream application data in and out of your application. But I'm
talking about application state, such as anything you have on a
per-connection or per-token basis, for example. It's in memory because it's
your application, not your application's data.
On Thu, May 31, 2012 at 1:21 PM, Paddy Byers <paddy.by...@gmail.com> wrote:
> Hi,
> If a collection is of "indefinite size" then it should not be loaded
>> entirely in to memory in order to accomplish computation, it should be
>> streamed. In the case of streaming the collection you can iteratively
>> perform the computation without locking up the process indefinitely and
>> without taking on a large memory footprint of either the original
>> collection or even what has already been processed.
> Yes, you stream application data in and out of your application. But I'm
> talking about application state, such as anything you have on a
> per-connection or per-token basis, for example. It's in memory because it's
> your application, not your application's data.
On May 31, 2012, at May 31, 20121:21 PM, Paddy Byers wrote:
> Hi,
> If a collection is of "indefinite size" then it should not be loaded entirely in to memory in order to accomplish computation, it should be streamed. In the case of streaming the collection you can iteratively perform the computation without locking up the process indefinitely and without taking on a large memory footprint of either the original collection or even what has already been processed.
> Yes, you stream application data in and out of your application. But I'm talking about application state, such as anything you have on a per-connection or per-token basis, for example. It's in memory because it's your application, not your application's data.
If that data is of "indefinite size" then it needs to be out of process. This is why Redis and memcache exist.
I don't see any argument for computationally intensive tasks on application data of "indefinite size" that much be entirely in process memory at one time.
>> On Tue, May 29, 2012 at 5:22 PM, Jorge <jo...@jorgechamorro.com> wrote:
>> FYI: setImmediate === nextTick and identical to a setTimeout(f,0) without the clamping.
> so I guess in a way setImmediate(fn) could be described fairly accurately as a faster setTimeout(fn, 0). As I understand timer events get put at the end of the queue as well.
> <snip>
LOL, see "nextTick(f) vs SetTimeout(f, 0)" (it's from ~ 2 years ago :-P):
Your explanation of the application state issue is very eloquent and matches my own reasoning.
@isaac, @mikeal,
This is turning into a real joke!
You tell us that you would like to change process.nextTick and you ask us for feedback.
Several people respond that this change is problematic for them and that they would much prefer that you introduce a *new* API and use it internally to solve your problems (and optionally make this new API public so that other people who have similar problems to solve can solve it the same way you do).
If you had listened to them, you'd have said: "ok guys, we understand that this is a problem for you; there is another easy path that solves the problem for us and won't put anyone else in trouble; let us do it." Case closed. Everyone can move forwards!
Instead you reply that anyway, the issue is already settled, the API will change, and all the people who are asking for process.nextTick to be preserved are just misusing node and need to rethink their applications with child processes.
If the issue was settled from the start anyway, you shouldn't have asked: just make the change and tell us afterwards! Don't pretend that you care about our opinion!
The problem is that people like me (I don't know about paddybyers but I'm assuming he is in a similar situation) are building real applications for real customers, not I/O libraries for other nodejs developers. And you guys simply don't know what building a real application means!
One thing you'll learn the day you build an application for real customers is that your audience is not made of geeks so you cannot tell them to just post a stacktrace on GitHub when something goes wrong. They don't know what a stacktrace is; they don't know what GitHub is either; they don't want to know what these things are; and there is no point trying to teach them! What they need is very robust exception handling and meaningful error messages. You'll also learn that you have to listen to what your customers say (behind every vocal customer, there are several silent ones).
Another thing you'll learn is that applications have "requirements". Everyone's not busy building the next Facebook. Some of use are building applications that will serve 1000 simultaneous users in the worst case. Some may even be building applications for very small businesses with less than 10 users. These applications may be less I/O intensive and more CPU intensive than the typical "next gen proxy" you have in mind. The people who are building them may have built similar applications on top of other stacks before. They probably know the CPU and I/O patterns that their applications have. They may be ready to trade a bit of "technical purity" for "pragmatic solutions", like building things that are not entirely stateless. And they may still have very valid reasons to want to build them on top of node.js rather than Ruby or PHP. They are probably not spending their days writing fibonacci or prime number generators, etc, etc.
So, when we tell you that we find process.nextTick useful because it allows us to time slice computations, it does not mean that we don't understand node. It just means that we know what we are building, that we have built similar things before with other stacks, that we have done our homework with the figures and that we consider that this approach is completely viable for *our* use cases.
So, please stop saying that we are doing things wrong and that our opinion should not matter. We are building real things and we know what we are doing. You just don't know what we are doing!
On Thursday, May 31, 2012 10:45:58 PM UTC+2, Mikeal Rogers wrote:
> On May 31, 2012, at May 31, 20121:21 PM, Paddy Byers wrote:
> Hi,
> If a collection is of "indefinite size" then it should not be loaded >> entirely in to memory in order to accomplish computation, it should be >> streamed. In the case of streaming the collection you can iteratively >> perform the computation without locking up the process indefinitely and >> without taking on a large memory footprint of either the original >> collection or even what has already been processed.
> Yes, you stream application data in and out of your application. But I'm > talking about application state, such as anything you have on a > per-connection or per-token basis, for example. It's in memory because it's > your application, not your application's data.
> If that data is of "indefinite size" then it needs to be out of process. > This is why Redis and memcache exist.
> I don't see any argument for computationally intensive tasks on > application data of "indefinite size" that much be entirely in process > memory at one time.
> On May 30, 2012, at 12:57 AM, Tim Caswell wrote
>>> On Tue, May 29, 2012 at 5:22 PM, Jorge <jo...@jorgechamorro.com> wrote:
>>> FYI: setImmediate === nextTick and identical to a setTimeout(f,0) without the clamping.
>> so I guess in a way setImmediate(fn) could be described fairly accurately as a faster setTimeout(fn, 0). As I understand timer events get put at the end of the queue as well.
>> <snip>
> LOL, see "nextTick(f) vs SetTimeout(f, 0)" (it's from ~ 2 years ago :-P):
> On Aug 29, 2010 6:43 PM, "Vitali Lovich" <vlov...@gmail.com> wrote:
>> That setTimeout(f, 0) can be optimized to perform significantly better than it currently does.
> Why complicate the code for a use case that shouldn't exist? Namely using setTimeout when you really mean nextTick.
Haha, nice. It's good to know that my outlook on things stays fairly
consistent. It's also interesting that everyone in that thread is pretty
much agreed that nextTick is a great idea and essential to node. But today
it's "ZOMG nextTick is horribly broken!". I guess that's called progress :)
On Fri, Jun 1, 2012 at 9:29 AM, Jorge <jo...@jorgechamorro.com> wrote:
> On May 30, 2012, at 12:57 AM, Tim Caswell wrote
> >> On Tue, May 29, 2012 at 5:22 PM, Jorge <jo...@jorgechamorro.com> wrote:
> >> FYI: setImmediate === nextTick and identical to a setTimeout(f,0)
> without the clamping.
> > so I guess in a way setImmediate(fn) could be described fairly
> accurately as a faster setTimeout(fn, 0). As I understand timer events get
> put at the end of the queue as well.
> > <snip>
> LOL, see "nextTick(f) vs SetTimeout(f, 0)" (it's from ~ 2 years ago :-P):
IMHO, node needs as few non-IO browser non-compliant APIs as possible. If
something like setImmediate will suffice, use it instead of nextTick. If
something like thisTick is necessary, ideally it would be done in pure
JavaScript or in a browser-compliant way so any modules depending on it can
more easily be ported to the browser.
For me, it's ultimately about code reuse, and node not
being perceived (valid or not) as a fork of JavaScript.The node and
JavaScript communities as a whole will be far better served with compatible
APIs. If an internal APi will suffice, keep it internal and use
setImmediate externally. If thisTick is necessary externally, if possible,
implement it in pure browser-compliant JavaScript a la Streams, etc...
On Fri, Jun 1, 2012 at 9:54 AM, Jorge <jo...@jorgechamorro.com> wrote:
> On Jun 1, 2012, at 6:29 PM, Jorge wrote:
> > On May 30, 2012, at 12:57 AM, Tim Caswell wrote
> >>> On Tue, May 29, 2012 at 5:22 PM, Jorge <jo...@jorgechamorro.com>
> wrote:
> >>> FYI: setImmediate === nextTick and identical to a setTimeout(f,0)
> without the clamping.
> >> so I guess in a way setImmediate(fn) could be described fairly
> accurately as a faster setTimeout(fn, 0). As I understand timer events get
> put at the end of the queue as well.
> >> <snip>
> > LOL, see "nextTick(f) vs SetTimeout(f, 0)" (it's from ~ 2 years ago :-P):
> On Aug 30, 2010, at 4:36 AM, Tim Caswell wrote
> > On Aug 29, 2010 6:43 PM, "Vitali Lovich" <vlov...@gmail.com> wrote:
> >> That setTimeout(f, 0) can be optimized to perform significantly better
> than it currently does.
> > Why complicate the code for a use case that shouldn't exist? Namely
> using setTimeout when you really mean nextTick.
> > <snip>
> :-P
> --
> Jorge.
-- Better a little with righteousness
than much gain with injustice.
Proverbs 16:8
On Fri, Jun 1, 2012 at 11:04 AM, Adam Crabtree <atcrabt...@gmail.com> wrote:
> IMHO, node needs as few non-IO browser non-compliant APIs as possible. If
> something like setImmediate will suffice, use it instead of nextTick. If
> something like thisTick is necessary, ideally it would be done in pure
> JavaScript or in a browser-compliant way so any modules depending on it can
> more easily be ported to the browser.
> For me, it's ultimately about code reuse, and node not
> being perceived (valid or not) as a fork of JavaScript.The node and
> JavaScript communities as a whole will be far better served with compatible
> APIs. If an internal APi will suffice, keep it internal and use
> setImmediate externally. If thisTick is necessary externally, if possible,
> implement it in pure browser-compliant JavaScript a la Streams, etc...
> Cheers,
> Adam Crabtree
> On Fri, Jun 1, 2012 at 9:54 AM, Jorge <jo...@jorgechamorro.com> wrote:
>> On Jun 1, 2012, at 6:29 PM, Jorge wrote:
>> > On May 30, 2012, at 12:57 AM, Tim Caswell wrote
>> >>> On Tue, May 29, 2012 at 5:22 PM, Jorge <jo...@jorgechamorro.com>
>> wrote:
>> >>> FYI: setImmediate === nextTick and identical to a setTimeout(f,0)
>> without the clamping.
>> >> so I guess in a way setImmediate(fn) could be described fairly
>> accurately as a faster setTimeout(fn, 0). As I understand timer events get
>> put at the end of the queue as well.
>> >> <snip>
>> > LOL, see "nextTick(f) vs SetTimeout(f, 0)" (it's from ~ 2 years ago
>> :-P):
>> On Aug 30, 2010, at 4:36 AM, Tim Caswell wrote
>> > On Aug 29, 2010 6:43 PM, "Vitali Lovich" <vlov...@gmail.com> wrote:
>> >> That setTimeout(f, 0) can be optimized to perform significantly better
>> than it currently does.
>> > Why complicate the code for a use case that shouldn't exist? Namely
>> using setTimeout when you really mean nextTick.
>> > <snip>
>> :-P
>> --
>> Jorge.
> --
> Better a little with righteousness
> than much gain with injustice.
> Proverbs 16:8
-- Better a little with righteousness
than much gain with injustice.
Proverbs 16:8
> You tell us that you would like to change process.nextTick and you ask us
> for feedback.
> Several people respond that this change is problematic for them and that
> they would much prefer that you introduce a *new* API and use it internally
> to solve your problems (and optionally make this new API public so that
> other people who have similar problems to solve can solve it the same way
> you do).
> If you had listened to them, you'd have said: "ok guys, we understand that
> this is a problem for you; there is another easy path that solves the
> problem for us and won't put anyone else in trouble; let us do it." Case
> closed. Everyone can move forwards!
> Instead you reply that anyway, the issue is already settled, the API will
> change, and all the people who are asking for process.nextTick to be
> preserved are just misusing node and need to rethink their applications
> with child processes.
> If the issue was settled from the start anyway, you shouldn't have asked:
> just make the change and tell us afterwards! Don't pretend that you care
> about our opinion!
Mostly agreed. The fact is the core guys do care about opinions. But they
often have biases about the way people "should" be using node. And if
you're not using it that way, it hurts your ability to argue successfully.
Node is opinionated, and Isaac and Mikeal in particular are opinionated.
That's the way this goes. Isaac is correct in saying we either change their
minds or we fork.
That said, I do wish they would come into conversations like this being a
little less smug and sure that they are right.
> The problem is that people like me (I don't know about paddybyers but I'm
> assuming he is in a similar situation) are building real applications for
> real customers, not I/O libraries for other nodejs developers. And you guys
> simply don't know what building a real application means!
> <snip>
This is all unnecessary, insulting, and untrue.
> So, when we tell you that we find process.nextTick useful because it
> allows us to time slice computations, it does not mean that we don't
> understand node. It just means that we know what we are building, that we
> have built similar things before with other stacks, that we have done our
> homework with the figures and that we consider that this approach is
> completely viable for *our* use cases.
> So, please stop saying that we are doing things wrong and that our opinion
> should not matter. We are building real things and we know what we are
> doing. You just don't know what we are doing!
> Please, listen to your customers!
I had a few thoughts about this. I also think the core guys are often
presumptuous about how people use node. But that speaks to their view of
the core principles of node. It's not necessarily about ignoring
constituencies. But about moving node towards their own vision. Even if it
means some previous usage is no longer well supported. You can't dictate
how people use your open source code, but there's an argument that you also
can't let that stop you from moving your project in the direction you want
it to go.
The only problem with this is that in so many other arenas, proposed
changes have been shot down out of hand because "people depend on it" or
"it would break a lot of code". It feels arbitrary to me when breaking
backwards compat is okay and when it's not. I have long been an advocate
that node can still change and we should continue to refine the api and
semantics. But I'm often on the losing end of that. But now we're taking an
extremely important, long standing core semantic and changing it. I guess I
just don't get it.
Also as for "listen to your customers", it also made me laugh. Because I
thought of the cliche that's frequently going around about startups. "If
you're not paying money, you're not the customer, you're the product". I
would add a corollary. "If you're not the customer or the product, then you
don't really matter". Not saying that applies here. But it's an interesting
line of thought.
While I find it flattering to be referred to as a "core guy" and I rarely correct people when they say it, you should know that I have less patches in to core than I have fingers.
One of the patches was quite large, but there are many people who spend far more time on core than I do.
What I spend most of my time on is building apps. I have a startup, I write lots of node.js code for it. I use node "properly" by some definition of "the way the APIs were intended to be used". I think many other people do the same.
You are absolutely correct that we cannot dictate how people *do* use an open source project. But, we can *recommend* a particular way and we shouldn't be concerned with breaking something that people do in a way we explicitly *do not recommend*.
This is node.js, we still break API in major releases. No way are we going to *not* change or break an API because people are using it in a way that was not intended and in fact we recommended them not to use it for. How can we possibly justify that when we break working APIs people are using as recommended all the time?
Node is not done. It needs to get better. We cannot improve it if we are not pushing it to its limits and the only way to do that is to use the right API for the right job. My insistence on use cases comes from *building apps* and wanting real needs to be demonstrated. My dismissal of use cases that are better fitted for another API come from handling may of these problems in the real world and seeing them easily solved by doing things the right way. We cannot move node forward if we're spending time optimizing use cases we agree are not being done the right way.
But, there are limitations in what we have recommended and in the current APIs. The current issues with nextTick() come problems we've found at scale doing things the recommended way.
-Mikeal
On Jun 1, 2012, at June 1, 201211:15 AM, Marco Rogers wrote:
> Man Bruno, you almost had a really strong message. But then you ruined it :)
> @isaac, @mikeal,
> This is turning into a real joke!
> Agreed
> You tell us that you would like to change process.nextTick and you ask us for feedback.
> Several people respond that this change is problematic for them and that they would much prefer that you introduce a *new* API and use it internally to solve your problems (and optionally make this new API public so that other people who have similar problems to solve can solve it the same way you do).
> If you had listened to them, you'd have said: "ok guys, we understand that this is a problem for you; there is another easy path that solves the problem for us and won't put anyone else in trouble; let us do it." Case closed. Everyone can move forwards!
> Instead you reply that anyway, the issue is already settled, the API will change, and all the people who are asking for process.nextTick to be preserved are just misusing node and need to rethink their applications with child processes.
> If the issue was settled from the start anyway, you shouldn't have asked: just make the change and tell us afterwards! Don't pretend that you care about our opinion!
> Mostly agreed. The fact is the core guys do care about opinions. But they often have biases about the way people "should" be using node. And if you're not using it that way, it hurts your ability to argue successfully. Node is opinionated, and Isaac and Mikeal in particular are opinionated. That's the way this goes. Isaac is correct in saying we either change their minds or we fork.
> That said, I do wish they would come into conversations like this being a little less smug and sure that they are right.
> The problem is that people like me (I don't know about paddybyers but I'm assuming he is in a similar situation) are building real applications for real customers, not I/O libraries for other nodejs developers. And you guys simply don't know what building a real application means!
> <snip>
> This is all unnecessary, insulting, and untrue.
> So, when we tell you that we find process.nextTick useful because it allows us to time slice computations, it does not mean that we don't understand node. It just means that we know what we are building, that we have built similar things before with other stacks, that we have done our homework with the figures and that we consider that this approach is completely viable for *our* use cases.
> So, please stop saying that we are doing things wrong and that our opinion should not matter. We are building real things and we know what we are doing. You just don't know what we are doing!
> Please, listen to your customers!
> I had a few thoughts about this. I also think the core guys are often presumptuous about how people use node. But that speaks to their view of the core principles of node. It's not necessarily about ignoring constituencies. But about moving node towards their own vision. Even if it means some previous usage is no longer well supported. You can't dictate how people use your open source code, but there's an argument that you also can't let that stop you from moving your project in the direction you want it to go.
> The only problem with this is that in so many other arenas, proposed changes have been shot down out of hand because "people depend on it" or "it would break a lot of code". It feels arbitrary to me when breaking backwards compat is okay and when it's not. I have long been an advocate that node can still change and we should continue to refine the api and semantics. But I'm often on the losing end of that. But now we're taking an extremely important, long standing core semantic and changing it. I guess I just don't get it.
> Also as for "listen to your customers", it also made me laugh. Because I thought of the cliche that's frequently going around about startups. "If you're not paying money, you're not the customer, you're the product". I would add a corollary. "If you're not the customer or the product, then you don't really matter". Not saying that applies here. But it's an interesting line of thought.
> a) "process_before_already_scheduled_events" - to address the main use-case, which is Isaac's proposed behaviour for nextTick;
> b) "schedule_after_already_scheduled_events" - to address the use case of being able to schedule work in parcels that would otherwise preempt event processing for unbounded time.
> (a) is a critical need, and the "official" purpose of nextTick, so its current behaviour is broken and it needs fixing to behave this way. There is an option to introduce a new more meaningful name and deprecate nextTick; but even then nextTick is obviously never going to go away, so it just needs to be very carefully documented and the name explained as an unfortunate artifact of history.
> (b) I believe is a genuine need and hopefully we can think of a good name for it, and implement it.
onIdle()
I have used nextTick where I am doing a background-like task that does not need to be run if there is lots going on, but useful to run when not busy. I had assumed nextTick would let anything that was waiting to run to be run.
First of all, Mikeal Rogers is not a "core guy who doesn't write
apps". Mikeal Rogers has written several apps with node, and has
authored very few patches to node core. He has a startup, and has
been building applications with Node since the 0.1 days.
And yes, I work on the node core project, but I'm also a Joyent
employee. My thoughts on this came from debugging node in production
applications at scale, especially the memory leaks and HTTP errors
that Voxer has seen on a regular basis. Also, some of these problems
have manifested in the node programs that Joyent uses to run data
centers for real customers, pushing loads of network traffic.
Our complicated nextTick semantics are causing real problems for real
applications. There is no ivory-tower-ism here. Node exists in the
real world. That's why we need to make nextTick work properly for the
cases where it's actually used. Complying with some notion of the
"correct" meaning of "tick" and "next" is completely not a priority.
I didn't ask for feedback as a joke. I asked for feedback because I
wanted to know what problems we would encounter if we changed nextTick
so that it actually works for its intended use case. The conclusion
that I eventually drew (the plan for node v0.9) is informed by that
feedback, and was not known at the outset.
There were two use cases presented in objection to the proposal:
1. Using process.nextTick to "break up" CPU intensive operations.
2. Using process.nextTick as an idle listener.
#2 is a valid use case for which there is no reasonable API at the
moment, but nextTick is *not* an idle listener anyway, since it will
frequently be fired in advance of pending IO. setTimeout(fn) is
better, but we probably ought to implement setImmediate or something
similar. That was new information, and is very useful. Thank you,
everyone.
#1 is not a valid use case. nextTick is horrible for this, I just
can't put it any other way. Either the operations are fast enough to
be done in a single thread, and a loop is fine, or they're not, and
you need to put them into a child process.
Meanwhile, we have lots of real world cases where nextTick is causing
actual problems for real applications. It's adding latency and
causing errors to be thrown. Phone conversations are interrupted by
it, and error pages are showing up in web browsers and applications.
It's an insidious bug that only manifests under load, and it must be
fixed.
Also, it seems that the documentation of process.nextTick needs to be
improved along with this change, because there is widespread
misunderstanding about how it ought to be used. The impression I'm
getting is that a lot of people treat nextTick a bit like a background
fork, and it's really not a good idea to use it that way.
Are there other new use cases not already brought up in this thread?
If so, please share them. They may make a big difference.
For those who feel disenfranchised by this decision, please consider
where I'm coming from. Half the people in node assumed that it worked
one way, and the other half believed it worked the other way, and in
fact, both were at least partly wrong. It's failing at its intended
purpose, and causing http to be subtly broken in some cases, which is
causing real world problems.
We can make node much more reliable for high-traffic HTTP servers
(which is what node is explicitly for), at the expense of making it
slightly worse at some approaches to high-CPU use cases (which is what
the child process API is for), and make node's internals simpler in
the process.
We can't please everyone. But please don't be so presumptuous to
assume that this is somehow about library authors being out of touch
with real world application developers. This is about choosing which
real world application developers to please, and which developers are
going to have to change their code.
> First of all, Mikeal Rogers is not a "core guy who doesn't write
> apps". Mikeal Rogers has written several apps with node, and has
> authored very few patches to node core. He has a startup, and has
> been building applications with Node since the 0.1 days.
> And yes, I work on the node core project, but I'm also a Joyent
> employee. My thoughts on this came from debugging node in production
> applications at scale, especially the memory leaks and HTTP errors
> that Voxer has seen on a regular basis. Also, some of these problems
> have manifested in the node programs that Joyent uses to run data
> centers for real customers, pushing loads of network traffic.
> Our complicated nextTick semantics are causing real problems for real
> applications. There is no ivory-tower-ism here. Node exists in the
> real world. That's why we need to make nextTick work properly for the
> cases where it's actually used. Complying with some notion of the
> "correct" meaning of "tick" and "next" is completely not a priority.
> I didn't ask for feedback as a joke. I asked for feedback because I
> wanted to know what problems we would encounter if we changed nextTick
> so that it actually works for its intended use case. The conclusion
> that I eventually drew (the plan for node v0.9) is informed by that
> feedback, and was not known at the outset.
> There were two use cases presented in objection to the proposal:
> 1. Using process.nextTick to "break up" CPU intensive operations.
> 2. Using process.nextTick as an idle listener.
> #2 is a valid use case for which there is no reasonable API at the
> moment, but nextTick is *not* an idle listener anyway, since it will
> frequently be fired in advance of pending IO. setTimeout(fn) is
> better, but we probably ought to implement setImmediate or something
> similar. That was new information, and is very useful. Thank you,
> everyone.
> #1 is not a valid use case. nextTick is horrible for this, I just
> can't put it any other way. Either the operations are fast enough to
> be done in a single thread, and a loop is fine, or they're not, and
> you need to put them into a child process.
> Meanwhile, we have lots of real world cases where nextTick is causing
> actual problems for real applications. It's adding latency and
> causing errors to be thrown. Phone conversations are interrupted by
> it, and error pages are showing up in web browsers and applications.
> It's an insidious bug that only manifests under load, and it must be
> fixed.
> Also, it seems that the documentation of process.nextTick needs to be
> improved along with this change, because there is widespread
> misunderstanding about how it ought to be used. The impression I'm
> getting is that a lot of people treat nextTick a bit like a background
> fork, and it's really not a good idea to use it that way.
> Are there other new use cases not already brought up in this thread?
> If so, please share them. They may make a big difference.
> For those who feel disenfranchised by this decision, please consider
> where I'm coming from. Half the people in node assumed that it worked
> one way, and the other half believed it worked the other way, and in
> fact, both were at least partly wrong. It's failing at its intended
> purpose, and causing http to be subtly broken in some cases, which is
> causing real world problems.
> We can make node much more reliable for high-traffic HTTP servers
> (which is what node is explicitly for), at the expense of making it
> slightly worse at some approaches to high-CPU use cases (which is what
> the child process API is for), and make node's internals simpler in
> the process.
> We can't please everyone. But please don't be so presumptuous to
> assume that this is somehow about library authors being out of touch
> with real world application developers. This is about choosing which
> real world application developers to please, and which developers are
> going to have to change their code.
I sometimes find myself in a place where I think "if this gets called
now, it'll go into a closed loop" so I use process.nextTick to break
out of that, but still retain the speed and order of my calls.
setTimeout(fn, 0) is too scary for orderly calls, even if it's
optimized now to act that way. I could have a custom queue and call
setTimeout(fn, 0) on that, or setImmediate if it ever comes around.
Basically now nextTick is like a setImmediate call with a fixed while
queue loop (fixed meaning you can't add to the queue while it's
running). Either way, it's a handy thing to have around, regardless
how you call it or how it's implemented.
> Great explanation Isaac, thanks for taking the time to write it.
> +1 to having nextTick work in a predictable way and updating the documentation to reflect that
> An idle event or async API would be useful to have.
> -- Dick
> On Jun 1, 2012, at 12:19 PM, Isaac Schlueter wrote:
>> First of all, Mikeal Rogers is not a "core guy who doesn't write
>> apps". Mikeal Rogers has written several apps with node, and has
>> authored very few patches to node core. He has a startup, and has
>> been building applications with Node since the 0.1 days.
>> And yes, I work on the node core project, but I'm also a Joyent
>> employee. My thoughts on this came from debugging node in production
>> applications at scale, especially the memory leaks and HTTP errors
>> that Voxer has seen on a regular basis. Also, some of these problems
>> have manifested in the node programs that Joyent uses to run data
>> centers for real customers, pushing loads of network traffic.
>> Our complicated nextTick semantics are causing real problems for real
>> applications. There is no ivory-tower-ism here. Node exists in the
>> real world. That's why we need to make nextTick work properly for the
>> cases where it's actually used. Complying with some notion of the
>> "correct" meaning of "tick" and "next" is completely not a priority.
>> I didn't ask for feedback as a joke. I asked for feedback because I
>> wanted to know what problems we would encounter if we changed nextTick
>> so that it actually works for its intended use case. The conclusion
>> that I eventually drew (the plan for node v0.9) is informed by that
>> feedback, and was not known at the outset.
>> There were two use cases presented in objection to the proposal:
>> 1. Using process.nextTick to "break up" CPU intensive operations.
>> 2. Using process.nextTick as an idle listener.
>> #2 is a valid use case for which there is no reasonable API at the
>> moment, but nextTick is *not* an idle listener anyway, since it will
>> frequently be fired in advance of pending IO. setTimeout(fn) is
>> better, but we probably ought to implement setImmediate or something
>> similar. That was new information, and is very useful. Thank you,
>> everyone.
>> #1 is not a valid use case. nextTick is horrible for this, I just
>> can't put it any other way. Either the operations are fast enough to
>> be done in a single thread, and a loop is fine, or they're not, and
>> you need to put them into a child process.
>> Meanwhile, we have lots of real world cases where nextTick is causing
>> actual problems for real applications. It's adding latency and
>> causing errors to be thrown. Phone conversations are interrupted by
>> it, and error pages are showing up in web browsers and applications.
>> It's an insidious bug that only manifests under load, and it must be
>> fixed.
>> Also, it seems that the documentation of process.nextTick needs to be
>> improved along with this change, because there is widespread
>> misunderstanding about how it ought to be used. The impression I'm
>> getting is that a lot of people treat nextTick a bit like a background
>> fork, and it's really not a good idea to use it that way.
>> Are there other new use cases not already brought up in this thread?
>> If so, please share them. They may make a big difference.
>> For those who feel disenfranchised by this decision, please consider
>> where I'm coming from. Half the people in node assumed that it worked
>> one way, and the other half believed it worked the other way, and in
>> fact, both were at least partly wrong. It's failing at its intended
>> purpose, and causing http to be subtly broken in some cases, which is
>> causing real world problems.
>> We can make node much more reliable for high-traffic HTTP servers
>> (which is what node is explicitly for), at the expense of making it
>> slightly worse at some approaches to high-CPU use cases (which is what
>> the child process API is for), and make node's internals simpler in
>> the process.
>> We can't please everyone. But please don't be so presumptuous to
>> assume that this is somehow about library authors being out of touch
>> with real world application developers. This is about choosing which
>> real world application developers to please, and which developers are
>> going to have to change their code.
Stop saying that the child process API is the answer to our problem: you don't know what our problem is and you are making up a solution that would not work for us.
process.nextTick is a non deteministic call and you want to turn it into a deterministic one because its non-determinism is breaking your code. I call this fixing a bug: your code is not robust enough to handle side effects caused by events that may interleave between nextTick calls and you need to eradicate these events to be on the safe side.
I have always assumed that nextTick would be non deterministic and I've designed my code to deal with this situation in a robust way. So your fix is not helping me in any way. On the other hand, I've designed my code with the assumption that nextTick would yield and let other events go through (and I remember asking a question about the starvation issue on this mailing list and getting a clarification from you saying that it did let other events go through). Your "fix" is breaking this assumption.
But you are in charge. So do as you like but be aware that this change is not innocuous and that some people have relied on what you told them a while ago and may be pissed off that you treat them so lightly.
And BTW, I don't make much difference between your use case #1 and #2. My use case is actually #2 and I would much prefer that my current nextTick calls be treated with low priority that with higher priority as they are today. So the 'onIdle' semantics are really what I'm looking for (as long as it is efficiently implemented so that onIdle runs as fast as possible when there is no I/O to process). Maybe we can come to an agreement in the end.
On Friday, June 1, 2012 9:19:03 PM UTC+2, Isaac Schlueter wrote:
> First of all, Mikeal Rogers is not a "core guy who doesn't write > apps". Mikeal Rogers has written several apps with node, and has > authored very few patches to node core. He has a startup, and has > been building applications with Node since the 0.1 days.
> And yes, I work on the node core project, but I'm also a Joyent > employee. My thoughts on this came from debugging node in production > applications at scale, especially the memory leaks and HTTP errors > that Voxer has seen on a regular basis. Also, some of these problems > have manifested in the node programs that Joyent uses to run data > centers for real customers, pushing loads of network traffic.
> Our complicated nextTick semantics are causing real problems for real > applications. There is no ivory-tower-ism here. Node exists in the > real world. That's why we need to make nextTick work properly for the > cases where it's actually used. Complying with some notion of the > "correct" meaning of "tick" and "next" is completely not a priority.
> I didn't ask for feedback as a joke. I asked for feedback because I > wanted to know what problems we would encounter if we changed nextTick > so that it actually works for its intended use case. The conclusion > that I eventually drew (the plan for node v0.9) is informed by that > feedback, and was not known at the outset.
> There were two use cases presented in objection to the proposal: > 1. Using process.nextTick to "break up" CPU intensive operations. > 2. Using process.nextTick as an idle listener.
> #2 is a valid use case for which there is no reasonable API at the > moment, but nextTick is *not* an idle listener anyway, since it will > frequently be fired in advance of pending IO. setTimeout(fn) is > better, but we probably ought to implement setImmediate or something > similar. That was new information, and is very useful. Thank you, > everyone.
> #1 is not a valid use case. nextTick is horrible for this, I just > can't put it any other way. Either the operations are fast enough to > be done in a single thread, and a loop is fine, or they're not, and > you need to put them into a child process.
> Meanwhile, we have lots of real world cases where nextTick is causing > actual problems for real applications. It's adding latency and > causing errors to be thrown. Phone conversations are interrupted by > it, and error pages are showing up in web browsers and applications. > It's an insidious bug that only manifests under load, and it must be > fixed.
> Also, it seems that the documentation of process.nextTick needs to be > improved along with this change, because there is widespread > misunderstanding about how it ought to be used. The impression I'm > getting is that a lot of people treat nextTick a bit like a background > fork, and it's really not a good idea to use it that way.
> Are there other new use cases not already brought up in this thread? > If so, please share them. They may make a big difference.
> For those who feel disenfranchised by this decision, please consider > where I'm coming from. Half the people in node assumed that it worked > one way, and the other half believed it worked the other way, and in > fact, both were at least partly wrong. It's failing at its intended > purpose, and causing http to be subtly broken in some cases, which is > causing real world problems.
> We can make node much more reliable for high-traffic HTTP servers > (which is what node is explicitly for), at the expense of making it > slightly worse at some approaches to high-CPU use cases (which is what > the child process API is for), and make node's internals simpler in > the process.
> We can't please everyone. But please don't be so presumptuous to > assume that this is somehow about library authors being out of touch > with real world application developers. This is about choosing which > real world application developers to please, and which developers are > going to have to change their code.
On Fri, Jun 1, 2012 at 12:19 PM, Isaac Schlueter <i...@izs.me> wrote:
> First of all, Mikeal Rogers is not a "core guy who doesn't write
> apps". Mikeal Rogers has written several apps with node, and has
> authored very few patches to node core. He has a startup, and has
> been building applications with Node since the 0.1 days.
Being a core guy has nothing to do with how many patches you have in core
or whether you also build apps. Felix builds apps. I have patches in core
but also build apps. Being a "core guy" means you have a tremendous amount
of influence on the way things go. If Mikeal did not agree with this
change, we would likely not be talking about it. Not saying you wouldn't
want to fix the core problem, but if Mikeal wanted to protect nextTick for
whatever reason, then changing it wouldn't be on the table. As opposed to
the rest of us who have to convince you not to change it, once you've
already decided it should be. That's what's happening here.
> And yes, I work on the node core project, but I'm also a Joyent
> employee. My thoughts on this came from debugging node in production
> applications at scale, especially the memory leaks and HTTP errors
> that Voxer has seen on a regular basis. Also, some of these problems
> have manifested in the node programs that Joyent uses to run data
> centers for real customers, pushing loads of network traffic.
> Our complicated nextTick semantics are causing real problems for real
> applications. There is no ivory-tower-ism here. Node exists in the
> real world. That's why we need to make nextTick work properly for the
> cases where it's actually used. Complying with some notion of the
> "correct" meaning of "tick" and "next" is completely not a priority.
Bullshit. Yes the tick semantics are complicated. But I think what you've
seen is that lots of people have built of their own mental model of how the
event loop works and use that mental model to good effect. These mental
models may be flawed but they are important. Reasoning about the async
nature of node is essential to getting it right. The reason this is even a
problem is at least partially due to getting this wrong in the first place.
I agree that this is about real applications, and I don't like the people
are jumping to conclusions. I'm referring to the meaning of "tick" and how
important it is to people understanding the "recommended" way of writing
proper node programs. Naming and consistency is a big part of building this
understanding. Please don't ignore this.
> I didn't ask for feedback as a joke. I asked for feedback because I
> wanted to know what problems we would encounter if we changed nextTick
> so that it actually works for its intended use case. The conclusion
> that I eventually drew (the plan for node v0.9) is informed by that
> feedback, and was not known at the outset.
> There were two use cases presented in objection to the proposal:
> 1. Using process.nextTick to "break up" CPU intensive operations.
> 2. Using process.nextTick as an idle listener.
> #2 is a valid use case for which there is no reasonable API at the
> moment, but nextTick is *not* an idle listener anyway, since it will
> frequently be fired in advance of pending IO. setTimeout(fn) is
> better, but we probably ought to implement setImmediate or something
> similar. That was new information, and is very useful. Thank you,
> everyone.
> #1 is not a valid use case. nextTick is horrible for this, I just
> can't put it any other way. Either the operations are fast enough to
> be done in a single thread, and a loop is fine, or they're not, and
> you need to put them into a child process.
This is where you're hubris is showing. Making this kind of presumption
requires you to dictate the constraints of another person's system. Maybe
your dataset doesn't stream. Maybe you can't use redis or memcache for some
reason. You keep using the wrong word to describe #1. It IS a valid use
case. It's just that you don't recommend it. And you are completely
ignoring the fact that it only became not recommended very recently, when
in fact we have been actively pushing people to next tick to defer
execution for a long time now. Now you've decided that it's not only "not
recommended" but a "bad idea". This is the height of presumption.
> Meanwhile, we have lots of real world cases where nextTick is causing
> actual problems for real applications. It's adding latency and
> causing errors to be thrown. Phone conversations are interrupted by
> it, and error pages are showing up in web browsers and applications.
> It's an insidious bug that only manifests under load, and it must be
> fixed.
> Also, it seems that the documentation of process.nextTick needs to be
> improved along with this change, because there is widespread
> misunderstanding about how it ought to be used. The impression I'm
> getting is that a lot of people treat nextTick a bit like a background
> fork, and it's really not a good idea to use it that way.
Yes, the reason there is a widespread misunderstanding is because it was
not misunderstood until a few days ago. And to be clear nextTick not being
used as "background fork". It's being used an efficient way to kill the
current stack to yield ongoing execution and let the event loop continue.
It's not about explicitly supporting "CPU intensive operations". For most
people it has always been a good practice before calling a callback if you
can't be sure if it's async. This has been a best practice of node for as
long as I can remember. yeilding to the event loop periodically protects
your throughput.
Consider functions that check a cache an in memory cache and return without
doing i/o. You don't want to have the callback by synchronous, so you throw
it into a nextTick call. That was literally a best practice until 2 days
ago. Now it's a terrible idea. Because if you r system ends up doing this
often, you are negatively affecting your i/o throughput because you're not
actually yielding to pending i/o. In practice, I don't think this will
happen often because most people are doing real i/o. But this IMO, the
potential for this biting people is just as likely as what is biting people
right now at high load. In fact, it's more insidious because people's
programs might not fail. They'll just see their throughput profiles change
and not really be sure why.
> Are there other new use cases not already brought up in this thread?
> If so, please share them. They may make a big difference.
> For those who feel disenfranchised by this decision, please consider
> where I'm coming from. Half the people in node assumed that it worked
> one way, and the other half believed it worked the other way, and in
> fact, both were at least partly wrong. It's failing at its intended
> purpose, and causing http to be subtly broken in some cases, which is
> causing real world problems.
We really would've tried to consider where you were coming from if you and
Mikeal had not started telling everyone how their applications were bad
because they dared to actually use nextTick in a context you don't approve
of (again a seemingly recent development).
As for how broken nextTick is, I think you're still missing the point of
why people feel disenfranchised. nextTick is behaving badly for some
people. And it's the people you are closest to. Your friends
and acquaintances who are building node apps, joyent customers who have
huge node deployments, or whatever. That's all fine and it's great that you
are trying to address their concerns. But as I said before, to say nextTick
is "broken" is to ignore everyone else who's telling you that it's not and
that we are using it just fine. You are confusing the importance of your
problem for the importance of the solution you've chosen. And my feeling is
that amount of code that will have to change because of this will be far
greater than the amount that will change if we provided a different
solution to the people who actually experience the data missing problem.
> We can make node much more reliable for high-traffic HTTP servers
> (which is what node is explicitly for), at the expense of making it
> slightly worse at some approaches to high-CPU use cases (which is what
> the child process API is for), and make node's internals simpler in
> the process.
> We can't please everyone. But please don't be so presumptuous to
> assume that this is somehow about library authors being out of touch
> with real world application developers. This is about choosing which
> real world application developers to please, and which developers are
> going to have to change their code.
This is a very reasonable statement. You are making a hard decision. And
you are seeing the consequences of it. I hope it works out for you. I have
put up with a lot of changes in node that I didn't agree with and I suspect
that most people will get over this one as well. But it seems like you guys
also want warm and fuzzies every time you make these hard decisions. That's
probably not going to happen.
On Jun 1, 2012, at June 1, 20121:09 PM, Marco Rogers wrote:
> On Fri, Jun 1, 2012 at 12:19 PM, Isaac Schlueter <i...@izs.me> wrote:
> First of all, Mikeal Rogers is not a "core guy who doesn't write
> apps". Mikeal Rogers has written several apps with node, and has
> authored very few patches to node core. He has a startup, and has
> been building applications with Node since the 0.1 days.
> Being a core guy has nothing to do with how many patches you have in core or whether you also build apps. Felix builds apps. I have patches in core but also build apps. Being a "core guy" means you have a tremendous amount of influence on the way things go. If Mikeal did not agree with this change, we would likely not be talking about it. Not saying you wouldn't want to fix the core problem, but if Mikeal wanted to protect nextTick for whatever reason, then changing it wouldn't be on the table. As opposed to the rest of us who have to convince you not to change it, once you've already decided it should be. That's what's happening here.
Several changes have gone in to node, in areas I have more influence than this, that I strongly disagreed with. The biggest being the removal of "pause" and "resume" events from Stream.pipe().
I doubt that, if I were so inclined, I could torpedo this change.
> And yes, I work on the node core project, but I'm also a Joyent
> employee. My thoughts on this came from debugging node in production
> applications at scale, especially the memory leaks and HTTP errors
> that Voxer has seen on a regular basis. Also, some of these problems
> have manifested in the node programs that Joyent uses to run data
> centers for real customers, pushing loads of network traffic.
> Our complicated nextTick semantics are causing real problems for real
> applications. There is no ivory-tower-ism here. Node exists in the
> real world. That's why we need to make nextTick work properly for the
> cases where it's actually used. Complying with some notion of the
> "correct" meaning of "tick" and "next" is completely not a priority.
> Bullshit. Yes the tick semantics are complicated. But I think what you've seen is that lots of people have built of their own mental model of how the event loop works and use that mental model to good effect. These mental models may be flawed but they are important. Reasoning about the async nature of node is essential to getting it right. The reason this is even a problem is at least partially due to getting this wrong in the first place.
> I agree that this is about real applications, and I don't like the people are jumping to conclusions. I'm referring to the meaning of "tick" and how important it is to people understanding the "recommended" way of writing proper node programs. Naming and consistency is a big part of building this understanding. Please don't ignore this.
I think what Isaac means is that the way people "think" nextTick() works is more important than what we can perceive the meaning of "next" and "tick" to mean on their own as words.
I think Isaac did a good job of showing that there are two interpretations of the current API that are actually both out of alignment with the current implementation. Making it fit one of those is more important than perceiving the meaning of "next" and "tick" trying to fit it.
In other words, Isaac is not trying to design a name to fit the API or making the API fit the exact meaning of the words, his goal is instead to make it fit one of the models people actually have for nextTick(). I believe his suggested solution for the other mental model for nextTick() is to add setImmediate.
> I didn't ask for feedback as a joke. I asked for feedback because I
> wanted to know what problems we would encounter if we changed nextTick
> so that it actually works for its intended use case. The conclusion
> that I eventually drew (the plan for node v0.9) is informed by that
> feedback, and was not known at the outset.
> There were two use cases presented in objection to the proposal:
> 1. Using process.nextTick to "break up" CPU intensive operations.
> 2. Using process.nextTick as an idle listener.
> #2 is a valid use case for which there is no reasonable API at the
> moment, but nextTick is *not* an idle listener anyway, since it will
> frequently be fired in advance of pending IO. setTimeout(fn) is
> better, but we probably ought to implement setImmediate or something
> similar. That was new information, and is very useful. Thank you,
> everyone.
> #1 is not a valid use case. nextTick is horrible for this, I just
> can't put it any other way. Either the operations are fast enough to
> be done in a single thread, and a loop is fine, or they're not, and
> you need to put them into a child process.
> This is where you're hubris is showing. Making this kind of presumption requires you to dictate the constraints of another person's system. Maybe your dataset doesn't stream. Maybe you can't use redis or memcache for some reason. You keep using the wrong word to describe #1. It IS a valid use case. It's just that you don't recommend it. And you are completely ignoring the fact that it only became not recommended very recently, when in fact we have been actively pushing people to next tick to defer execution for a long time now. Now you've decided that it's not only "not recommended" but a "bad idea". This is the height of presumption.
If a compelling enough argument can be made for this use case then I don't think we'll fight a solution that fits it. What we are saying is that nextTick() does *not* fit it and it's being used for this case at the moment because we've failed to provide a better solution.
I'm the one who doubts the validity of the use case entirely, specifically I contend that the solution to processing a collection of "indefinite size" should not ever be handled by loading the entire thing in to finite memory.
> Meanwhile, we have lots of real world cases where nextTick is causing
> actual problems for real applications. It's adding latency and
> causing errors to be thrown. Phone conversations are interrupted by
> it, and error pages are showing up in web browsers and applications.
> It's an insidious bug that only manifests under load, and it must be
> fixed.
> Also, it seems that the documentation of process.nextTick needs to be
> improved along with this change, because there is widespread
> misunderstanding about how it ought to be used. The impression I'm
> getting is that a lot of people treat nextTick a bit like a background
> fork, and it's really not a good idea to use it that way.
> Yes, the reason there is a widespread misunderstanding is because it was not misunderstood until a few days ago. And to be clear nextTick not being used as "background fork". It's being used an efficient way to kill the current stack to yield ongoing execution and let the event loop continue. It's not about explicitly supporting "CPU intensive operations". For most people it has always been a good practice before calling a callback if you can't be sure if it's async. This has been a best practice of node for as long as I can remember. yeilding to the event loop periodically protects your throughput.
> Consider functions that check a cache an in memory cache and return without doing i/o. You don't want to have the callback by synchronous, so you throw it into a nextTick call. That was literally a best practice until 2 days ago. Now it's a terrible idea.
That use case is solved just as well with the change that Isaac is proposing. The only use case that his proposed change steps on is CPU intensive operations that might starve IO.
Regardless of peoples' impression of nextTick() your use case here will work as well after this change as before it. Technically, it'll be a little faster.
> Because if you r system ends up doing this often, you are negatively affecting your i/o throughput because you're not actually yielding to pending i/o. In practice, I don't think this will happen often because most people are doing real i/o. But this IMO, the potential for this biting people is just as likely as what is biting people right now at high load. In fact, it's more insidious because people's programs might not fail. They'll just see their throughput profiles change and not really be sure why.
Not true. You're talking about adding a single handler, not recursively adding handlers forever, and I'm not seeing a case where you could ever do so many of these legitimately that aren't on their own CPU intensive that you would starve IO.
From what I can tell this use case will work better and won't starve IO unless you have a bug where you're recursively adding handlers forever.
If you do add so many handlers recursively that you starve IO then you'll hit the guard I already proposed, so it will fail.
> Are there other new use cases not already brought up in this thread?
> If so, please share them. They may make a big difference.
> For those who feel disenfranchised by this decision, please consider
> where I'm coming from. Half the people in node assumed that it worked
> one way, and the other half believed it worked the other way, and in
> fact, both were at least partly wrong. It's failing at its intended
> purpose, and causing http to be subtly broken in some cases, which is
> causing real world problems.
> We really would've tried to consider where you were coming from if you and Mikeal had not started telling everyone how their applications were bad because they dared to actually use nextTick in a context you don't approve of (again a seemingly recent development).
You make it sound like we called all these developers names, we didn't. We said "that's not what this is for, that's what this other thing is for." A perfectly valid point for a
...
On Fri, Jun 1, 2012 at 1:09 PM, Marco Rogers <marco.rog...@gmail.com> wrote:
> Being a "core guy" means you have a tremendous amount of
> influence on the way things go. If Mikeal did not agree with this change, we
> would likely not be talking about it. Not saying you wouldn't want to fix
> the core problem, but if Mikeal wanted to protect nextTick for whatever
> reason, then changing it wouldn't be on the table.
That's false. Mikeal's been in the dissenting minority plenty of
times, and has had to deal with changes he didn't like, and has pet
features of his pulled out because they caused problems.
> The reason this is even a
> problem is at least partially due to getting this wrong in the first place.
No disagreement there.
> This is where you're hubris is showing. Making this kind of presumption
> requires you to dictate the constraints of another person's system. Maybe
> your dataset doesn't stream. Maybe you can't use redis or memcache for some
> reason.
So, you're saying that there are, today, in the real world,
applications where you must iterate over a work queue that is:
1. Impossible to serialize in a child process.
2. Arbitrarily large.
3. Small enough to fit in memory.
4. Well-partitioned enough to split up into multiple passes.
5. Important enough to risk affecting IO performance by shoving a very
high priority uv listener into the queue.
6. Not so important to starve IO while all the passes complete.
Show me. That's a pretty narrow use case. I'm skeptical, but you
know how much I love being surprised by evidence :)
In any contest between "maybe someone will need this, how do you know
they don't?" and "this is a known problem for current HTTP servers and
clients", our choice is obvious.
We try very hard in node to deal with reality over hypotheticals. If
there are real world cases that are currently best served by the
current nextTick (as opposed to, say, a proper idle listener, a child
process, or a end-of-tick handler), then we'll address it.
> And you are completely ignoring
> the fact that it only became not recommended very recently, when in fact we
> have been actively pushing people to next tick to defer execution for a long
> time now. Now you've decided that it's not only "not recommended" but a "bad
> idea". This is the height of presumption.
Not "recently". Qv. every "node sucks" article that points at CPU
bottlenecks. Put CPU intensive operations into a child process.
That's node's concurrency story. It's not new.
> And to be clear nextTick not being used
> as "background fork". It's being used an efficient way to kill the current
> stack to yield ongoing execution and let the event loop continue.
In some of your comments here, it sounds like you might be confusing
the run-to-completion behavior with the IO event loop. RTC isn't
going to change, and nextTick will still be the approved way to
schedule behavior that happens after anything else in the current v8
invocation. It'll just happen *immediately* after, instead of in a
high-priority uv listener.
Just to be 100% clear, the behavior of this code won't change:
var foo = new EventEmitter
process.nextTick(function () {
foo.emit('bar', 'baz')
})
foo.on('bar', console.log)
Both with the change, and without it, this program will log 'baz'.
However, this program will (maybe) be affected:
process.nextTick(function f () {
process.nextTick(f)
})
setTimeout(function () {
console.log('bar')
}, 100)
Also, we can probably figure out a way to make it work such that it
runs the first nextTick at the end of the current RTC, but subsequent
ones at some point get deferred. As I said earlier in the thread, we
haven't investigated it thoroughly.
> Consider functions that check a cache an in memory cache and return without
> doing i/o. You don't want to have the callback by synchronous, so you throw
> it into a nextTick call.
That's still going to be the case. In fact, that *doesn't* work very
reliably right now, and is nondeterministically slow. It *will* work
reliably with this change, and with lower latency. That's what this
is all about.
> That was literally a best practice until 2 days
> ago. Now it's a terrible idea. Because if you r system ends up doing this
> often, you are negatively affecting your i/o throughput because you're not
> actually yielding to pending i/o.
It would only be the case if you have a nextTick that adds another
nextTick, forever. That would have the same performance
characteristics as an infinite loop.
We could add a nextTickDepth guard or something, and make it so that
process.nextTick(function f(){process.nextTick(f)}) will do a
setTimeout(f, 0) after 100,000 recursions or something. That'll be
still on the order of a few ms, and it'll *still* be a few orders of
magnitude faster for any use case presented. That's all still TBD.
> As for how broken nextTick is, I think you're still missing the point of why
> people feel disenfranchised. nextTick is behaving badly for some people. And
> it's the people you are closest to.
In my capacity as the person in charge of the node.js project, I am
closest to those who are pushing node's limits and using it in the
real world under high production loads.
So, yes, I agree with you here.
> But as I said before, to say nextTick is "broken" is to
> ignore everyone else who's telling you that it's not and that we are using
> it just fine.
If you do a lot of HTTP requests under extremely high load, you'll see
sporadic failures in the agent code.
It's not "just fine". It's "just fine for small n". Everything is
fine for small n. Node is for high traffic applications.
High-traffic problems are our problems.
There's currently no good way to assign a handler to the end of the current RTC.