Zero-cost futures in Rust
321–330 of 348 posts
Re: Zero-cost futures in Rust
#322Earlier quoted context omitted.
The real cost of a true "context switch" is the transition from user level to kernel level, which takes thousands of cycles. This cost isn't incurred on a userland context switch, so those costs aren't comparable.
Thousands of cycles for a SYSCALL/SYSRET on a reasonably modern Intel/AMD CPU? I think you should try to measure that.
Re: Zero-cost futures in Rust
#323Earlier quoted context omitted.
> You can recover most of the M:N ergonomics over time via async/await style syntax. While i agree with the tradeoff made by rust (although i think the approach used by C++ coroutine is better), i don't think that having async/await syntax give you "most" of the ergonomics of the Go M:N model . The main advantage of the go model is that both asynchronous and synchronous operations are identical, with async/await you…
> although i think the approach used by C++ coroutine is better How? > The main advantage of the go model is that both asynchronous and synchronous operations are identical, with async/await you still need to model the async operation and the sync operation with different types. It's more like "everything is synchronous" in the Go model. Semantically, Go doesn't have async I/O at all. It has a userspace M:N implement…
1 - Waiting for the future to complete before exiting the current function (which essentially is blocking)
2 - Allocating the closure on th heap (allocation + deallocation)
In a language with coroutine support , we have a third alternative. Instead of block or allocating memory, it's possible to just suspend the current function (no heap allocation necessary, no blocking), and resume when the future completes.
In term of context switching speed : the cost of moving the state machine is essentially the cost of a double dispatch (probably double dispatch plus virtual function call), switching coroutines is closer to the cost of a function call ( i think it's cheaper than a normal function call, but tha becomes too technical)
Re: Zero-cost futures in Rust
#324Earlier quoted context omitted.
> although i think the approach used by C++ coroutine is better How? > The main advantage of the go model is that both asynchronous and synchronous operations are identical, with async/await you still need to model the async operation and the sync operation with different types. It's more like "everything is synchronous" in the Go model. Semantically, Go doesn't have async I/O at all. It has a userspace M:N implement…
> How ? In term of allocation : When the future uses some variable present on the current function stack you have two options 1 - Waiting for the future to complete before exiting the current function (which essentially is blocking) 2 - Allocating the closure on th heap (allocation + deallocation) In a language with coroutine support , we have a third alternative. Instead of block or allocating memory, it's possible…
Re: Zero-cost futures in Rust
#325How are futures handled for open() and disk i/o?
Re: Zero-cost futures in Rust
#326select is an odd term choice for what is essentially a race condition. What's the thought behind the naming of that method?
Re: Zero-cost futures in Rust
#327Earlier quoted context omitted.
No program beyond the most trivial will meet these requirements. The moment you call any function indirectly you lose.
Yes, but indirectly means "&Fn", but not "&F where F: Fn". And a whole program doesn't need to conform, only individual threads. Presumably the ones you want to make a lot of. (And if a little dynamicism was required, its expense could be paid for at the use, by creating a fresh necessary-sized stack at that point. But I'm probably opening up old split-stack wounds, sorry)
Re: Zero-cost futures in Rust
#328Earlier quoted context omitted.
The blocking (i.e. synchronous) syscalls for IO are doing asynchronous things internally, they just wait for the event to finish before returning. The kernel can even do similar scheduling things to a language runtime, e.g. when a thread does a call to a blocking read on a socket, the thread can be switched out until the socket actually has data, allowing other code to run on that core.
I am still unclear on how does that correlate to the orignal discussion. The point we were debating is whether or not Golang does async io. I am not sure why the kernel behavior is important here
This is exactly the same as using normal blocking operations with OS threads. That programming model is synchronous: the code executes an IO operation and that thread of execution halts until the operation completes. The kernel is implemented using asynchronous IO internally, and manages scheduling between threads itself, but that is an implementation detail.
The original point is Go's programming model is the same as OS-level blocking IO, the fact the runtime is implemented in user-space on top of async IO is an implementation detail that doesn't change the surface behaviour of the code. One could substitute OS threads and normal OS blocking calls for goroutines and the runtime's IO operations and code would behave essentially identically, just possibly with different performance characteristics.
Re: Zero-cost futures in Rust
#329Earlier quoted context omitted.
The real cost of a true "context switch" is the transition from user level to kernel level, which takes thousands of cycles. This cost isn't incurred on a userland context switch, so those costs aren't comparable.
Thousands of cycles for a SYSCALL/SYSRET on a reasonably modern Intel/AMD CPU? I think you should try to measure that.
Re: Zero-cost futures in Rust
#330Earlier quoted context omitted.
> Fair enough, but kernel stacks are 8K. And getting even cheaper than that, with the effort to make kernel stacks use virtual memory. As I understand it, once kernel stacks use virtual memory, they'll start out at a single 4k page.
Is there a writeup somewhere of the progress towards this, or a prospective timeline?