-
Notifications
You must be signed in to change notification settings - Fork 30.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
streams: add cork option to pipe #2020
Conversation
Curious: why not just call |
cork knows about the high water mark? There's something I must be misunderstanding. |
@@ -333,6 +333,8 @@ readable.isPaused() // === false | |||
* `destination` {[Writable][] Stream} The destination for writing data | |||
* `options` {Object} Pipe options | |||
* `end` {Boolean} End the writer when the reader ends. Default = `true` | |||
* `cork` {Boolean} Before each write cork the stream and then uncork it on the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
there should probably be a comma after Before each write
@chrisdickinson because then you have to wait until you hit the highwatermark before you actually write anything, see the comment by @indutny in the readable stream issue |
debug('corking'); | ||
corked = true; | ||
dest.cork(); | ||
process.nextTick(function () { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder if pulling this anonymous function out of maybeCork()
would help performance-wise?
OK, I was wrong – cork and uncork have no idea about highwatermark. That said, I'm not sure I'm fully on board with this change (though I may be misunderstanding it.) So, to check my assumptions about how streams work (and in particular, how net.Streams work):
Right now streams will be flushing chunks without using |
Adds an option to .pipe to cork it before each write and then uncork it next tick, based on discussion at nodejs/readable-stream#145
Things that could cause my assumptions to be incorrect:
These both seem like TCP-specific concerns – it might be better to solve them at the |
This is the more general benefit that could apply to other streams that want to strike a balance between per write overhead and latency |
Just for reference, this is basically the same thing the http module does today. |
Another key component in this is the interaction with uv_try_write. You want to immediately write out as much as the kernel can handle then queue the remaining. It's not uncommon that all writes can be done immediately. This affects all uv_stream_t instances. |
@mscdex updated based on your suggestions |
@trevnorris still it is faster to do just one |
@indutny internally doesn't it automatically write out as much as possible using uv_try_write before setting up the WriteReq? |
Yes, but it will pass multiple buffers as a single input with writev. |
Sure, but uv_try_write only takes one at a time. That's what I was trying to get at above. Thought it may be a performance advantage to write immediately until uv_try_write fails, then queue up the remaining for writev. Simply because between the first set of running uv_try_write the kernel may have flushed some of the data and could accept more when writev ran. But the timing could also be so minimal that it doesn't really matter. |
Not really, it takes multiple: UV_EXTERN int uv_try_write(uv_stream_t* handle,
const uv_buf_t bufs[],
unsigned int nbufs); |
Though, your comments are quite correct. I am not suggesting this should be a default behavior in any way. But for my use case it would be beneficial to introduce this option, otherwise I will need to concatenate the buffers manually in memory. |
Doh. Memory failure. Thanks for correcting me. My comment was more just an observation I realized while looking over this PR. Definitely not something I think should be introduced in this PR. :-) |
We're talking about bringing back Based on this comment, it seems like you should be seeing at least one writev of size N>1. Is the problem that:
|
@chrisdickinson they can't happen because I am piping to the socket, not writing to it myself. So every write results in separate |
I have a use-case where I'm piping from a _transform to a writable, and would benefit from the same solution. For me however, nextTick would be overkill (not sure what the cost of a nexttick is tbh), as _transform already uses a callback to denote the end of a batch of writes. Perhaps the transform use case could be optimized? |
@@ -515,9 +518,26 @@ Readable.prototype.pipe = function(dest, pipeOpts) { | |||
ondrain(); | |||
} | |||
|
|||
function maybeCork() { | |||
if (!autoCork || corked) { | |||
debug('already corked'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not technically correct in the case of autoCork being false.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
True should be more like, 'no need to cork'
I just submitted #2167 which I think might really benefit from this. |
@@ -467,6 +467,9 @@ Readable.prototype.pipe = function(dest, pipeOpts) { | |||
dest !== process.stdout && | |||
dest !== process.stderr; | |||
|
|||
var autoCork = pipeOpts && pipeOpts.cork && (typeof dest.cork === 'function'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a time when dest.cork
isn't a function? Won't it error anyways if it isn't a writable stream?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Old streams?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, that makes sense! Thanks!
@calvinmetcalf ... ping ... is this still something you'd like to pursue? |
sure I can rebase |
closing this as I'm not so sure we need this |
Adds an option to .pipe to cork it before each write and
then uncork it next tick, based on discussion at
nodejs/readable-stream#145