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
Rust-dev@mozilla.org
https://mail.mozilla.org/listinfo/rust-dev

Reply via email to