On 30/04/2013 12:17 PM, james wrote:
This is what I call blocking synchronous read, a 'pull' model.  Its
hardly different
from a threaded rogram with a userspace switch and sync to async call
translation,
whether N:1 or N:M.  Granted that the compiler support for task switch
points and
segmented stack make the tasks more lightweight.

Ok. Then yes, we're presenting a 'pull' model. On top of an AIO model. which itself may (on many kernels or C libraries) map to a pull model (and goodness knows what combination of push, pull and poll happening inside the hardware). You may be surprised how often an "AIO" call in a C library winds up resulting in a thread spawning and making a blocking call. But whatever.

It may well be what most people want most of the time, but history is so
far unkind
to N:M threading, and people used to writing highly scalable servers (a
minority,
perhaps) are used to thinking in terms of event processing.

This response is a bit hard to take. It amounts to "what most people want most of the time is not what a few people want some of the time, so we should force everyone to do the latter". This is not how library design works.

High performance servers tend to use a mixture of thread pools, event interfaces, offload devices like sendfile/TransmitFile/splice, scatter/gather, multiple processes and every other trick under the sun. There's no way to make those tricks all play nicely with a composable, friendly, sequential, "what most users want most of the time" programming model.

We'll expose what we can with the caveats that each API requires. We'll make the APIs as findable and usable as we can. We're _not_ going to require users to write to the most elaborate possible high-performance interface when they want to open a file and read bytes from it. That's a simple task and demands a simple API. We'll try to make it fast, not block other tasks, and compose nicely.

(It's also the case that the failure of M:N threading _in C_ mostly relates to the kernel threads getting fast enough that 1:1 was viable. To support sequential execution in C code and multiplex it at the kernel level and still win performance benchmarks against M:N. Which is the opposite of the argument you're making. But anyways.)

The design focus would appear to on synchronous semantics.  I would
prefer async
and an easy way to chain things together and wait with a future.  I
would at least ask
that the lower level API not be second-class citizen.

The "design focus" is (presently) on what people keep asking for: "I would like to be able to read lines from a file without the other tasks on my thread blocking and without having to wire up an overly-complex callback thing against libuv's low level interface".

What makes an API a second class citizen? If we expose both, and 99% of users who want to open a file and read it prefer:

  let in = File::new_read("foo.txt");
  let out = File::new_write("bar.txt");
  for in.lines |line| {
      if line.contains("bleh") {
          out.write(line);
      }
  }
  // control gets here => lines are written

over

  let in = File::new_read("foo.txt");
  do in.read |buf| {
      let out = File::new_write("bar.txt");
      do out.create |fh| {
          let lines = str::lines(buf);
          fn write_line(i: int) {
              if i < lines.len() && lines[i].contains("bleh") {
                  do fh.write(lines[i]) |fh| {
                      write_line(i+1);
                  }
              }
          }
          write_line(0);
      }
  }
  // NB: control arrived here before any
  // of the above I/O happened.

is it our fault that users prefer the first, and will you think we've done an unfair job and made it "second class" if so?

-Graydon

_______________________________________________
Rust-dev mailing list
[email protected]
https://mail.mozilla.org/listinfo/rust-dev

Reply via email to