From 589d2c746edb77831e4d99bb5890631de5744d5d Mon Sep 17 00:00:00 2001 From: Olivier Saut Date: Thu, 16 May 2013 14:05:53 +0200 Subject: [PATCH 1/8] Correct the example given for a future, add punctuation where necessary --- src/libstd/future.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/libstd/future.rs b/src/libstd/future.rs index be33c0f4663ed..028dcf0f06206 100644 --- a/src/libstd/future.rs +++ b/src/libstd/future.rs @@ -1,4 +1,4 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -15,9 +15,9 @@ * # Example * * ~~~ - * let delayed_fib = future::spawn {|| fib(5000) }; + * let mut delayed_fib = future::spawn (|| fib(5000) ); * make_a_sandwich(); - * io::println(fmt!("fib(5000) = %?", delayed_fib.get())) + * println(fmt!("fib(5000) = %?", delayed_fib.get())) * ~~~ */ @@ -51,7 +51,7 @@ priv enum FutureState { /// Methods on the `future` type pub impl Future { fn get(&mut self) -> A { - //! Get the value of the future + //! Get the value of the future. *(self.get_ref()) } } @@ -87,7 +87,7 @@ pub impl Future { pub fn from_value(val: A) -> Future { /*! - * Create a future from a value + * Create a future from a value. * * The value is immediately available and calling `get` later will * not block. @@ -117,7 +117,7 @@ pub fn from_fn(f: ~fn() -> A) -> Future { /*! * Create a future from a function. * - * The first time that the value is requested it will be retreived by + * The first time that the value is requested it will be retrieved by * calling the function. Note that this function is a local * function. It is not spawned into another task. */ From 0895f728ef5fe7dc6319cbe10103c91710e260bb Mon Sep 17 00:00:00 2001 From: Olivier Saut Date: Thu, 16 May 2013 14:07:13 +0200 Subject: [PATCH 2/8] Add a small section on futures to the tutorial, remove use task::spawn as it is now included by default in prelude.rs --- doc/tutorial-tasks.md | 72 +++++++++++++++++++++++++++++++++++-------- 1 file changed, 59 insertions(+), 13 deletions(-) diff --git a/doc/tutorial-tasks.md b/doc/tutorial-tasks.md index 402cfa84afcba..b315bcb6fece6 100644 --- a/doc/tutorial-tasks.md +++ b/doc/tutorial-tasks.md @@ -43,15 +43,16 @@ in the core and standard libraries, which are still under development and do not always present a consistent or complete interface. For your reference, these are the standard modules involved in Rust -concurrency at this writing. +concurrency at this writing: -* [`core::task`] - All code relating to tasks and task scheduling -* [`core::comm`] - The message passing interface -* [`core::pipes`] - The underlying messaging infrastructure -* [`std::comm`] - Additional messaging types based on `core::pipes` -* [`std::sync`] - More exotic synchronization tools, including locks +* [`core::task`] - All code relating to tasks and task scheduling, +* [`core::comm`] - The message passing interface, +* [`core::pipes`] - The underlying messaging infrastructure, +* [`std::comm`] - Additional messaging types based on `core::pipes`, +* [`std::sync`] - More exotic synchronization tools, including locks, * [`std::arc`] - The ARC (atomically reference counted) type, - for safely sharing immutable data + for safely sharing immutable data, +* [`std::future`] - A type representing values that may be computed concurrently and retrieved at a later time. [`core::task`]: core/task.html [`core::comm`]: core/comm.html @@ -59,6 +60,7 @@ concurrency at this writing. [`std::comm`]: std/comm.html [`std::sync`]: std/sync.html [`std::arc`]: std/arc.html +[`std::future`]: std/future.html # Basics @@ -70,7 +72,7 @@ closure in the new task. ~~~~ # use core::io::println; -use core::task::spawn; +# use core::task::spawn; // Print something profound in a different task using a named function fn print_message() { println("I am running in a different task!"); } @@ -145,8 +147,8 @@ endpoint. Consider the following example of calculating two results concurrently: ~~~~ -use core::task::spawn; -use core::comm::{stream, Port, Chan}; +# use core::task::spawn; +# use core::comm::{stream, Port, Chan}; let (port, chan): (Port, Chan) = stream(); @@ -233,7 +235,8 @@ Instead we can use a `SharedChan`, a type that allows a single ~~~ # use core::task::spawn; -use core::comm::{stream, SharedChan}; +# use core::comm::{stream, SharedChan}; +use core::comm::SharedChan; let (port, chan) = stream(); let chan = SharedChan::new(chan); @@ -282,6 +285,49 @@ let result = ports.foldl(0, |accum, port| *accum + port.recv() ); # fn some_expensive_computation(_i: uint) -> int { 42 } ~~~ +## Futures +With `std::future`, rust has a mechanism for requesting a computation and getting the result +later. + +The basic example below illustrates this. +~~~ +fn fib(n: uint) -> uint { + // lengthy computation returning an uint +} + +let mut delayed_fib = future::spawn (|| fib(5000) ); +make_a_sandwich(); +println(fmt!("fib(5000) = %?", delayed_fib.get())) +~~~ + +The call to `future::spawn` returns immediately a `future` object regardless of how long it +takes to run `fib(5000)`. You can then make yourself a sandwich while the computation of `fib` is +running. The result of the execution of the method is obtained by calling `get` on the future. +This call will block until the value is available (*i.e.* the computation is complete). Note that +the future needs to be mutable so that it can save the result for next time `get` is called. + +Here is another example showing how futures allow you to background computations. The workload will +be distributed on the available cores. +~~~ +fn partial_sum(start: uint) -> f64 { + let mut local_sum = 0f64; + for uint::range(start*100000, (start+1)*100000) |num| { + local_sum += (num as f64 + 1).pow(-2.0); + } + local_sum +} + +fn main() { + let mut futures = vec::from_fn(1000, |ind| do std::future::spawn { partial_sum(ind) }); + + let mut final_res = 0f64; + for futures.each_mut |ft| { + final_res += ft.get(); + } + println(fmt!("π^2/6 is not far from : %?", final_res)); +} +~~~ + # Handling task failure Rust has a built-in mechanism for raising exceptions. The `fail!()` macro @@ -363,8 +409,8 @@ either task fails, it kills the other one. ~~~ # fn sleep_forever() { loop { task::yield() } } # do task::try { -do task::spawn { - do task::spawn { +do spawn { + do spawn { fail!(); // All three tasks will fail. } sleep_forever(); // Will get woken up by force, then fail From 93b4a57b9a774ec781b6609119f0dad00af489b6 Mon Sep 17 00:00:00 2001 From: Olivier Saut Date: Thu, 16 May 2013 16:05:04 +0200 Subject: [PATCH 3/8] Fix typo --- doc/tutorial-tasks.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/tutorial-tasks.md b/doc/tutorial-tasks.md index b315bcb6fece6..515c97329c9ce 100644 --- a/doc/tutorial-tasks.md +++ b/doc/tutorial-tasks.md @@ -312,7 +312,7 @@ be distributed on the available cores. fn partial_sum(start: uint) -> f64 { let mut local_sum = 0f64; for uint::range(start*100000, (start+1)*100000) |num| { - local_sum += (num as f64 + 1).pow(-2.0); + local_sum += (num as f64 + 1.0).pow(-2.0); } local_sum } From bf619469b52e5fe18ab84d81adbc147206cd9b92 Mon Sep 17 00:00:00 2001 From: Olivier Saut Date: Fri, 17 May 2013 18:42:43 +0200 Subject: [PATCH 4/8] Correct failing tests --- doc/tutorial-tasks.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/doc/tutorial-tasks.md b/doc/tutorial-tasks.md index 515c97329c9ce..93ce54af03a04 100644 --- a/doc/tutorial-tasks.md +++ b/doc/tutorial-tasks.md @@ -236,7 +236,6 @@ Instead we can use a `SharedChan`, a type that allows a single ~~~ # use core::task::spawn; # use core::comm::{stream, SharedChan}; -use core::comm::SharedChan; let (port, chan) = stream(); let chan = SharedChan::new(chan); @@ -291,13 +290,15 @@ later. The basic example below illustrates this. ~~~ +# fn make_a_sandwich() {}; fn fib(n: uint) -> uint { // lengthy computation returning an uint + 12586269025 } -let mut delayed_fib = future::spawn (|| fib(5000) ); +let mut delayed_fib = std::future::spawn (|| fib(50) ); make_a_sandwich(); -println(fmt!("fib(5000) = %?", delayed_fib.get())) +println(fmt!("fib(50) = %?", delayed_fib.get())) ~~~ The call to `future::spawn` returns immediately a `future` object regardless of how long it From e23243cf67d816bdc93ab6ac4b53898b9575f3c0 Mon Sep 17 00:00:00 2001 From: Olivier Saut Date: Thu, 16 May 2013 14:05:53 +0200 Subject: [PATCH 5/8] Correct the example given for a future, add punctuation where necessary --- src/libstd/future.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/libstd/future.rs b/src/libstd/future.rs index be33c0f4663ed..028dcf0f06206 100644 --- a/src/libstd/future.rs +++ b/src/libstd/future.rs @@ -1,4 +1,4 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -15,9 +15,9 @@ * # Example * * ~~~ - * let delayed_fib = future::spawn {|| fib(5000) }; + * let mut delayed_fib = future::spawn (|| fib(5000) ); * make_a_sandwich(); - * io::println(fmt!("fib(5000) = %?", delayed_fib.get())) + * println(fmt!("fib(5000) = %?", delayed_fib.get())) * ~~~ */ @@ -51,7 +51,7 @@ priv enum FutureState { /// Methods on the `future` type pub impl Future { fn get(&mut self) -> A { - //! Get the value of the future + //! Get the value of the future. *(self.get_ref()) } } @@ -87,7 +87,7 @@ pub impl Future { pub fn from_value(val: A) -> Future { /*! - * Create a future from a value + * Create a future from a value. * * The value is immediately available and calling `get` later will * not block. @@ -117,7 +117,7 @@ pub fn from_fn(f: ~fn() -> A) -> Future { /*! * Create a future from a function. * - * The first time that the value is requested it will be retreived by + * The first time that the value is requested it will be retrieved by * calling the function. Note that this function is a local * function. It is not spawned into another task. */ From 185d5ce494b812cf291365d3390431522da2abfb Mon Sep 17 00:00:00 2001 From: Olivier Saut Date: Thu, 16 May 2013 14:07:13 +0200 Subject: [PATCH 6/8] Add a small section on futures to the tutorial, remove use task::spawn as it is now included by default in prelude.rs --- doc/tutorial-tasks.md | 72 +++++++++++++++++++++++++++++++++++-------- 1 file changed, 59 insertions(+), 13 deletions(-) diff --git a/doc/tutorial-tasks.md b/doc/tutorial-tasks.md index 402cfa84afcba..b315bcb6fece6 100644 --- a/doc/tutorial-tasks.md +++ b/doc/tutorial-tasks.md @@ -43,15 +43,16 @@ in the core and standard libraries, which are still under development and do not always present a consistent or complete interface. For your reference, these are the standard modules involved in Rust -concurrency at this writing. +concurrency at this writing: -* [`core::task`] - All code relating to tasks and task scheduling -* [`core::comm`] - The message passing interface -* [`core::pipes`] - The underlying messaging infrastructure -* [`std::comm`] - Additional messaging types based on `core::pipes` -* [`std::sync`] - More exotic synchronization tools, including locks +* [`core::task`] - All code relating to tasks and task scheduling, +* [`core::comm`] - The message passing interface, +* [`core::pipes`] - The underlying messaging infrastructure, +* [`std::comm`] - Additional messaging types based on `core::pipes`, +* [`std::sync`] - More exotic synchronization tools, including locks, * [`std::arc`] - The ARC (atomically reference counted) type, - for safely sharing immutable data + for safely sharing immutable data, +* [`std::future`] - A type representing values that may be computed concurrently and retrieved at a later time. [`core::task`]: core/task.html [`core::comm`]: core/comm.html @@ -59,6 +60,7 @@ concurrency at this writing. [`std::comm`]: std/comm.html [`std::sync`]: std/sync.html [`std::arc`]: std/arc.html +[`std::future`]: std/future.html # Basics @@ -70,7 +72,7 @@ closure in the new task. ~~~~ # use core::io::println; -use core::task::spawn; +# use core::task::spawn; // Print something profound in a different task using a named function fn print_message() { println("I am running in a different task!"); } @@ -145,8 +147,8 @@ endpoint. Consider the following example of calculating two results concurrently: ~~~~ -use core::task::spawn; -use core::comm::{stream, Port, Chan}; +# use core::task::spawn; +# use core::comm::{stream, Port, Chan}; let (port, chan): (Port, Chan) = stream(); @@ -233,7 +235,8 @@ Instead we can use a `SharedChan`, a type that allows a single ~~~ # use core::task::spawn; -use core::comm::{stream, SharedChan}; +# use core::comm::{stream, SharedChan}; +use core::comm::SharedChan; let (port, chan) = stream(); let chan = SharedChan::new(chan); @@ -282,6 +285,49 @@ let result = ports.foldl(0, |accum, port| *accum + port.recv() ); # fn some_expensive_computation(_i: uint) -> int { 42 } ~~~ +## Futures +With `std::future`, rust has a mechanism for requesting a computation and getting the result +later. + +The basic example below illustrates this. +~~~ +fn fib(n: uint) -> uint { + // lengthy computation returning an uint +} + +let mut delayed_fib = future::spawn (|| fib(5000) ); +make_a_sandwich(); +println(fmt!("fib(5000) = %?", delayed_fib.get())) +~~~ + +The call to `future::spawn` returns immediately a `future` object regardless of how long it +takes to run `fib(5000)`. You can then make yourself a sandwich while the computation of `fib` is +running. The result of the execution of the method is obtained by calling `get` on the future. +This call will block until the value is available (*i.e.* the computation is complete). Note that +the future needs to be mutable so that it can save the result for next time `get` is called. + +Here is another example showing how futures allow you to background computations. The workload will +be distributed on the available cores. +~~~ +fn partial_sum(start: uint) -> f64 { + let mut local_sum = 0f64; + for uint::range(start*100000, (start+1)*100000) |num| { + local_sum += (num as f64 + 1).pow(-2.0); + } + local_sum +} + +fn main() { + let mut futures = vec::from_fn(1000, |ind| do std::future::spawn { partial_sum(ind) }); + + let mut final_res = 0f64; + for futures.each_mut |ft| { + final_res += ft.get(); + } + println(fmt!("π^2/6 is not far from : %?", final_res)); +} +~~~ + # Handling task failure Rust has a built-in mechanism for raising exceptions. The `fail!()` macro @@ -363,8 +409,8 @@ either task fails, it kills the other one. ~~~ # fn sleep_forever() { loop { task::yield() } } # do task::try { -do task::spawn { - do task::spawn { +do spawn { + do spawn { fail!(); // All three tasks will fail. } sleep_forever(); // Will get woken up by force, then fail From dc7aa94c661c57dc4c24aaca85760384325b987a Mon Sep 17 00:00:00 2001 From: Olivier Saut Date: Thu, 16 May 2013 16:05:04 +0200 Subject: [PATCH 7/8] Fix typo --- doc/tutorial-tasks.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/tutorial-tasks.md b/doc/tutorial-tasks.md index b315bcb6fece6..515c97329c9ce 100644 --- a/doc/tutorial-tasks.md +++ b/doc/tutorial-tasks.md @@ -312,7 +312,7 @@ be distributed on the available cores. fn partial_sum(start: uint) -> f64 { let mut local_sum = 0f64; for uint::range(start*100000, (start+1)*100000) |num| { - local_sum += (num as f64 + 1).pow(-2.0); + local_sum += (num as f64 + 1.0).pow(-2.0); } local_sum } From 0e8d227666628adad66dad3533c747c8ea2afe6a Mon Sep 17 00:00:00 2001 From: Olivier Saut Date: Fri, 17 May 2013 18:42:43 +0200 Subject: [PATCH 8/8] Correct failing tests --- doc/tutorial-tasks.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/doc/tutorial-tasks.md b/doc/tutorial-tasks.md index 515c97329c9ce..93ce54af03a04 100644 --- a/doc/tutorial-tasks.md +++ b/doc/tutorial-tasks.md @@ -236,7 +236,6 @@ Instead we can use a `SharedChan`, a type that allows a single ~~~ # use core::task::spawn; # use core::comm::{stream, SharedChan}; -use core::comm::SharedChan; let (port, chan) = stream(); let chan = SharedChan::new(chan); @@ -291,13 +290,15 @@ later. The basic example below illustrates this. ~~~ +# fn make_a_sandwich() {}; fn fib(n: uint) -> uint { // lengthy computation returning an uint + 12586269025 } -let mut delayed_fib = future::spawn (|| fib(5000) ); +let mut delayed_fib = std::future::spawn (|| fib(50) ); make_a_sandwich(); -println(fmt!("fib(5000) = %?", delayed_fib.get())) +println(fmt!("fib(50) = %?", delayed_fib.get())) ~~~ The call to `future::spawn` returns immediately a `future` object regardless of how long it