I see several proposals for the future of Rust tasks, and I think one of the
best approaches is being overlooked, and that is something similar to async in
C# (http://msdn.microsoft.com/en-us/library/vstudio/hh191443.aspx).
In C#, the "async" keyword can be applied to functions and it causes the
compiler to transform a function that returns T into a function that returns a
Task<T> (which is C#'s name for a future of type T) representing the
potentially asynchronous computation.
Blocking is representing by using the "await" keyword on a future (typically
returned by a call to another "async" function), and it causes the compiler to
perform a Continuation-Passing Style transformation, and attach the
continuation to the future, returning another future representing the composed
computation.
I/O functions are designed to return futures, so in this system blocking causes
all calling "async" functions to return, building up a chain of continuations
on the heap, which is equivalent to the machine stack in a current-Rust task,
but which is as small as needed, and is only used for call chains that block.
In Rust, this transformation is much more delicate, because the resulting
return value futures must have a lifetime that is the smallest among all the
arguments to the function, if those arguments are needed by the continuation,
and the argument types must be "shareable" between parallel forks (e.g.
std::rc::Rc is not shareable because RC manipulation is non-atomic).
However, it is possible to restrict the system to use non-delimited
continuations instead of the delimited continuations and futures, which would
avoid this problem, since futures cannot be used explicitly anymore (at the
cost of making flexible parallelism impossible).
In this latter case, it would be equivalent to the current task system, except
for requiring blocking functions to be marked "async"; the "await" keyword
would not be required, since it would effectively become compulsory if there
are no first-class futures returned for async functions.
Advantages:
- Functions and interfaces that can perform I/O or can block are clearly marked
by a keyword
- Can have billions of blocked tasks (with hundreds of gigabytes of RAM) since
the memory used by each blocked task is truly minimized because it's on the heap
Disadvantages:
- Requires an heap allocation for every function call to an async function (to
hold the continuation data)
- Non-"async" functions cannot call "async" functions, so interfaces must be
explicitly marked as async or not
- Requires to implement the transform in the compiler
Microsoft switched to this paradigm in the latest version of C# and in the
Windows RT API, and it might be an appropriate choice for Rust too.
_______________________________________________
Rust-dev mailing list
[email protected]
https://mail.mozilla.org/listinfo/rust-dev