Am 29.01.2013 02:29, schrieb Graydon Hoare:
On 13-01-28 04:56 PM, Brian Anderson wrote:

I think libuv is doing too much here. For example, if I don't want to
remove the socket from the event
queue, just disable the callback, then this is not possible. I'd
prefer when I could just tell libuv that
I am interested in event X (on Windows: I/O completion, on UNIX: I/O
availability).
Yet the optimization you suggest has to do with recycling the buffer,
not listening for one kind of event vs. another.

In general I'm not interested in trying to "get underneath" the
abstraction uv is providing. It's providing an IOCP-oriented interface,
I would like to code to that and make the rust IO library not have to
worry when it's on windows vs. unix. That's the point of the abstraction
uv provides, and it's valuable. If it means bouncing off epoll a few too
many times (or reallocating a buffer a few too many times), I'm not too
concerned. Those should both be O(1) operations.

I think allocating a buffer performs much better than waking up the event loop for every read, because waking up the event loop involves kernel activity on both
scheduler and iotask, while malloc should in most cases be pure user-level.
And allocating buffers allows us to asynchronously continue reading while the task is still doing some computations. If we would allow multiple readers on a single port (do we? I think channels in Go allow that), then we would even have a very simple way to load balance I/O to multiple tasks. This could actually make sense in many scenarios. Kind of work-stealing. And we could build arbitrary pipelines. Of course we can simulate the same by using a dispatcher task, but this would incur some overhead.

Is it possible to do this optimization later or do we need to plan for
this ahead of time? I would prefer to use the uv API as it's presented
to start with.
The optimization to use a caller-provided buffer should (a) not be
necessary to get us started and (b) be equally possible on either
platform, unix or windows, _so long as_ we're actually sleeping a task
during its period of interest in IO (either the pre-readiness sleep or a
post-issue, pre-completion sleep). In other words, if we're simulating
sync IO, then we can use a task-local buffer. If we're _not_ simulating
sync IO (I sure hope we do!) then we should let uv allocate and free
dynamic buffers as it needs them.

We are kind of simulating sync IO by using a channel. But IO would be async in the
background (if we do not want to wakup the event loop for every read), so we
would need buffers.

But I really hope we wind up structuring it so it simulates sync IO.
We're providing a task abstraction. Users _want_ the sync IO abstraction
the same way they want the sequential control flow abstraction.

Yes. I (now) fully agree.

(Indeed, on an appropriately-behaving system I fully expect task=thread
and sync IO calls=system calls)

If using a "SizedChannel(1)" each io.recv would correspond to one read() syscall, except that the syscall could have happend long ago. Channels with longer queues would mean
that up to "n" (size of queue) read() calls could have happend.

Regards,

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

Reply via email to