- From: ??? <willchan@chromium.org>
- Date: Mon, 14 Jul 2014 15:13:05 -0700
- To: Domenic Denicola <domenic@domenicdenicola.com>
- Cc: "whatwg@lists.whatwg.org" <whatwg@lists.whatwg.org>, "Tab Atkins Jr." <jackalmage@gmail.com>, Juan Ignacio Dopazo <jdopazo@yahoo-inc.com>
On Mon, Jul 14, 2014 at 8:56 AM, Domenic Denicola < domenic@domenicdenicola.com> wrote: > From: whatwg <whatwg-bounces@lists.whatwg.org> on behalf of Domenic > Denicola <domenic@domenicdenicola.com> > > > Of these, 1 seems much nicer, based on my Node.js experience. > > To be clearer as to why this is: stream APIs work much better when things > you write to are represented as writable streams (option 1), instead of > representing them as functions that accept readable streams (option 2). Can you explain this in more detail? AFAICT, the fundamental difference we're talking about here is push vs pull sources. Option 1 is a push model, where fetch() creates a writable stream that has an underlying sink (Domenic, did I get that right? I assume you meant sink and not source) of the request body. And the user code writes to the stream to stream output to the request body. In contrast, option 2 is a pull model, where fetch() accepts as input a readable stream and pulls from it as the network is ready to write the request body out. I'm willing to believe that the push model might result in easier APIs for piping. I haven't thought about it. But I want to assert that the push model has significant downsides in comparison to the pull model. First, observe that a stream is a reliable (in the network sense, a la TCP), ordered sequence of data. The reliability and ordering requirement are key to understanding the performance issues. That effectively transforms a stream into a FIFO queue. The sooner you push data into a FIFO queue, the sooner the source has to commit to the ordering of data. Now, observe that committing to the ordering of data sooner prevents the source from reordering later. Why might one want to reorder later? Prioritization. Delaying the binding of data to a stream allows the source to better prioritize data. For example, let's say that I have a server. I have multiple clients issuing requests. I have a single backend connection (database backend, file serving backend, whatever). So I'm multiplexing requests from multiple clients over a single connection. If I want to prioritize the order in which I utilize the single backend [connection], I had best delay the commit of a request blob to the backend connection stream. It's better for the backend connection stream to *pull* rather than for the server to *push* to the backend, because it facilitates this delayed decision making process. For a real example of the push vs pull model and its relation to prioritization, I've got an old blog post ( https://insouciant.org/tech/prioritization-only-works-when-theres-pending-data-to-prioritize/) I wrote before about Google Maps engineers complaining to me that prioritization didn't work. The root cause of the problem was the push model and excessive buffering (in the kernel sink, which defeated our user space prioritization at the source). Of course, you can simulate a pull model with a push model by applying backpressure super aggressively, which I discuss later on in that same blog post ( https://insouciant.org/tech/prioritization-only-works-when-theres-pending-data-to-prioritize/#The_Solution). By reducing the amount of buffering, you incur more context switches instead. In the blog post, a context switch is an actual kernel / user space OS context switch. In a web browser model, it would be a context switch between the different layers within the browser platform and the user code, which can get especially expensive in a multiprocess resource loading model, such as the one that the Chromium browser uses. There are many other nuances here but I've neglected to mention out of brevity. Let me know if more details would help. Cheers. PS: I document many of my/Chromium's struggles to undo the push model in our network stack and the resulting payoffs here - https://insouciant.org/tech/connection-management-in-chromium/#socket_late_binding .
Received on Monday, 14 July 2014 22:13:29 UTC