auto merge of #6752 : osaut/rust/tutorial-tasks, r=graydon
* Add a short section and an example illustrating the use of ARC. * Header for the section of Future changed to be more descriptive: "Backgrounding computations: Futures".
This commit is contained in:
commit
6d7d759129
@ -284,7 +284,7 @@ let result = ports.foldl(0, |accum, port| *accum + port.recv() );
|
||||
# fn some_expensive_computation(_i: uint) -> int { 42 }
|
||||
~~~
|
||||
|
||||
## Futures
|
||||
## Backgrounding computations: Futures
|
||||
With `extra::future`, rust has a mechanism for requesting a computation and getting the result
|
||||
later.
|
||||
|
||||
@ -329,6 +329,77 @@ fn main() {
|
||||
}
|
||||
~~~
|
||||
|
||||
## Sharing immutable data without copy: ARC
|
||||
|
||||
To share immutable data between tasks, a first approach would be to only use pipes as we have seen
|
||||
previously. A copy of the data to share would then be made for each task. In some cases, this would
|
||||
add up to a significant amount of wasted memory and would require copying the same data more than
|
||||
necessary.
|
||||
|
||||
To tackle this issue, one can use an Atomically Reference Counted wrapper (`ARC`) as implemented in
|
||||
the `extra` library of Rust. With an ARC, the data will no longer be copied for each task. The ARC
|
||||
acts as a reference to the shared data and only this reference is shared and cloned.
|
||||
|
||||
Here is a small example showing how to use ARCs. We wish to run concurrently several computations on
|
||||
a single large vector of floats. Each task needs the full vector to perform its duty.
|
||||
~~~
|
||||
use extra::arc::ARC;
|
||||
|
||||
fn pnorm(nums: &~[float], p: uint) -> float {
|
||||
(vec::foldl(0.0, *nums, |a,b| a+(*b).pow(p as float) )).pow(1f / (p as float))
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let numbers=vec::from_fn(1000000, |_| rand::random::<float>());
|
||||
println(fmt!("Inf-norm = %?", numbers.max()));
|
||||
|
||||
let numbers_arc = ARC(numbers);
|
||||
|
||||
for uint::range(1,10) |num| {
|
||||
let (port, chan) = stream();
|
||||
chan.send(numbers_arc.clone());
|
||||
|
||||
do spawn {
|
||||
let local_arc : ARC<~[float]> = port.recv();
|
||||
let task_numbers = local_arc.get();
|
||||
println(fmt!("%u-norm = %?", num, pnorm(task_numbers, num)));
|
||||
}
|
||||
}
|
||||
}
|
||||
~~~
|
||||
|
||||
The function `pnorm` performs a simple computation on the vector (it computes the sum of its items
|
||||
at the power given as argument and takes the inverse power of this value). The ARC on the vector is
|
||||
created by the line
|
||||
~~~
|
||||
# use extra::arc::ARC;
|
||||
# let numbers=vec::from_fn(1000000, |_| rand::random::<float>());
|
||||
let numbers_arc=ARC(numbers);
|
||||
~~~
|
||||
and a clone of it is sent to each task
|
||||
~~~
|
||||
# use extra::arc::ARC;
|
||||
# let numbers=vec::from_fn(1000000, |_| rand::random::<float>());
|
||||
# let numbers_arc = ARC(numbers);
|
||||
# let (port, chan) = stream();
|
||||
chan.send(numbers_arc.clone());
|
||||
~~~
|
||||
copying only the wrapper and not its contents.
|
||||
|
||||
Each task recovers the underlying data by
|
||||
~~~
|
||||
# use extra::arc::ARC;
|
||||
# let numbers=vec::from_fn(1000000, |_| rand::random::<float>());
|
||||
# let numbers_arc=ARC(numbers);
|
||||
# let (port, chan) = stream();
|
||||
# chan.send(numbers_arc.clone());
|
||||
# let local_arc : ARC<~[float]> = port.recv();
|
||||
let task_numbers = local_arc.get();
|
||||
~~~
|
||||
and can use it as if it were local.
|
||||
|
||||
The `arc` module also implements ARCs around mutable data that are not covered here.
|
||||
|
||||
# Handling task failure
|
||||
|
||||
Rust has a built-in mechanism for raising exceptions. The `fail!()` macro
|
||||
|
Loading…
Reference in New Issue
Block a user