@@ -284,7 +284,7 @@ let result = ports.foldl(0, |accum, port| *accum + port.recv() );
284284# fn some_expensive_computation(_i: uint) -> int { 42 }
285285~~~
286286
287- ## Futures
287+ ## Backgrounding computations: Futures
288288With ` extra::future ` , rust has a mechanism for requesting a computation and getting the result
289289later.
290290
@@ -329,6 +329,77 @@ fn main() {
329329}
330330~~~
331331
332+ ## Sharing immutable data without copy: ARC
333+
334+ To share immutable data between tasks, a first approach would be to only use pipes as we have seen
335+ previously. A copy of the data to share would then be made for each task. In some cases, this would
336+ add up to a significant amount of wasted memory and would require copying the same data more than
337+ necessary.
338+
339+ To tackle this issue, one can use an Atomically Reference Counted wrapper (` ARC ` ) as implemented in
340+ the ` extra ` library of Rust. With an ARC, the data will no longer be copied for each task. The ARC
341+ acts as a reference to the shared data and only this reference is shared and cloned.
342+
343+ Here is a small example showing how to use ARCs. We wish to run concurrently several computations on
344+ a single large vector of floats. Each task needs the full vector to perform its duty.
345+ ~~~
346+ use extra::arc::ARC;
347+
348+ fn pnorm(nums: &~[float], p: uint) -> float {
349+ (vec::foldl(0.0, *nums, |a,b| a+(*b).pow(p as float) )).pow(1f / (p as float))
350+ }
351+
352+ fn main() {
353+ let numbers=vec::from_fn(1000000, |_| rand::random::<float>());
354+ println(fmt!("Inf-norm = %?", numbers.max()));
355+
356+ let numbers_arc = ARC(numbers);
357+
358+ for uint::range(1,10) |num| {
359+ let (port, chan) = stream();
360+ chan.send(numbers_arc.clone());
361+
362+ do spawn {
363+ let local_arc : ARC<~[float]> = port.recv();
364+ let task_numbers = local_arc.get();
365+ println(fmt!("%u-norm = %?", num, pnorm(task_numbers, num)));
366+ }
367+ }
368+ }
369+ ~~~
370+
371+ The function ` pnorm ` performs a simple computation on the vector (it computes the sum of its items
372+ at the power given as argument and takes the inverse power of this value). The ARC on the vector is
373+ created by the line
374+ ~~~
375+ # use extra::arc::ARC;
376+ # let numbers=vec::from_fn(1000000, |_| rand::random::<float>());
377+ let numbers_arc=ARC(numbers);
378+ ~~~
379+ and a clone of it is sent to each task
380+ ~~~
381+ # use extra::arc::ARC;
382+ # let numbers=vec::from_fn(1000000, |_| rand::random::<float>());
383+ # let numbers_arc = ARC(numbers);
384+ # let (port, chan) = stream();
385+ chan.send(numbers_arc.clone());
386+ ~~~
387+ copying only the wrapper and not its contents.
388+
389+ Each task recovers the underlying data by
390+ ~~~
391+ # use extra::arc::ARC;
392+ # let numbers=vec::from_fn(1000000, |_| rand::random::<float>());
393+ # let numbers_arc=ARC(numbers);
394+ # let (port, chan) = stream();
395+ # chan.send(numbers_arc.clone());
396+ # let local_arc : ARC<~[float]> = port.recv();
397+ let task_numbers = local_arc.get();
398+ ~~~
399+ and can use it as if it were local.
400+
401+ The ` arc ` module also implements ARCs around mutable data that are not covered here.
402+
332403# Handling task failure
333404
334405Rust has a built-in mechanism for raising exceptions. The ` fail!() ` macro
0 commit comments