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 }
|
# 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
|
With `extra::future`, rust has a mechanism for requesting a computation and getting the result
|
||||||
later.
|
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
|
# Handling task failure
|
||||||
|
|
||||||
Rust has a built-in mechanism for raising exceptions. The `fail!()` macro
|
Rust has a built-in mechanism for raising exceptions. The `fail!()` macro
|
||||||
|
Loading…
Reference in New Issue
Block a user