Friday
Jul132018

Rayon Makes Rust Worthwhile

Rust 1.27 the programming language, I think I like, well,  I like it mostly I guess.  Ownership, borrowing, bracebracket parenthesis <> syntax that chaffes against other computer language conventions.  Getting a for-loop to step is like pulling teeth.  Variable type conversion is formal enough to call it not exactly automatic.  Data abstraction and data structure options are lovely, as best I can tell, so long as you don't yearn for a concurrently accessed, circular dynamically linked lists without begining or end... like "ten million cpu workers weeding god-only-knowns how much ringworld data fields in forever forward marching cycles" - well if that's your thing, Rust might trigger intense emotional responses from time to time.

Cargo, the package manager is well done, and so use it well because of built in feature/function minimalism.  Rust seems lean in file build size.  Compile time optimizations are off by default leading first time users to think rust runs slow. Scope, borrowing and ownership rules are first time user mischief makers - don't worry, soon enough they will be your best friends.  Vector implementations are richly typed*- HA that's a joke, as in you'll do lots of typing- on the keyboard.  Get it?    Maybe that's more confusing than funny,  but I like to think its funny because its true: Let ha_ha : Vec<usize> = Vec::new();  ha_ha.push(1);  ha_ha.push(2);   

But despite no small amount of quirk and sass, Rust feels like the future of computer programming to me.

Why? That rust aims for a systems programming mission trifectia of safe speedy concurrency by almost banning garbage collection, race conditions, segfaults, memory leaks, sloppy variable type conversion and buffer overruns helps.   But those same things also make rust feel like the programming equivalent of wearing stilts - great strides are easy but there are downsides.  So what makes rust loveable?    

In part, the aforementioned loveable mischief makers, powerful strides made following two rules that keep you safe and still the ability to ditch the rules, pretty good compiler feedback, and at least one amazing multi-thread processing crate.        

RAYON!  Rayon is a external crate for rust and is sweet way to multithread.  The only way I could be more impressed would be if it supported both GPUs and CPUs.  Consider the following toy prime finding program (coded by me except for the square root function supplied by users.rust-lang.org/t/integer-square-root-algorithm/13529/13 user Leonardo and displayed beautifully in InteliJ J IDEA with integerated developer enviroment code tweaks with the text tucked under the image:

 


extern crate rayon; use std::time::Instant; use rayon::prelude::*; fn isqrt(num: u32) -> u32 { let r= (num as f64).sqrt() as u32; //float point precision vs integer discrete if r<4096 {return r} // compute root of num and return, large root may have error delta (num/r + r)/2 // so divide num by delta root for anti-delta root, average result & return } } fn prime_b(testprime:u32, primelist:&Vec) -> bool { let limit = isqrt(testprime); //run ordered low to high, no reason to check above square root let mut prime:bool = false; //default assumption is not a prime 'calculation: for i in primelist{ if *i > limit { prime=true; //if i is larger than test limit num must be prime break 'calculation;} //example 7: 7%2 !=0, 7%3 else { if testprime % *i == 0 { //if remainder is 0, testprime is not a prime, break 'calculation; } // break calculation loop } } return prime } fn main() { let mut known_primes:Vec = Vec::new(); known_primes.extend([2,3,5,7,11].iter()); let start_timer= Instant::now(); for _building_knowledge in 1..4 { //knowledge loop splits finding primes and adding them to list of known primes let mut start_at :u32= 1+ &known_primes[&known_primes.len() - 1] ; //start after last prime found let mut block_end :u32= &start_at * &start_at - 1; //for odd prime n, n^2 not prime, n^2 -1 %2 is even ∴ not prime let found_primes:Vec = (start_at..block_end) .into_par_iter() .filter_map(|x| { if prime_b(x,&known_primes) {Some(x)} else {None } } ) .collect(); }//End of building knowledge scope, now found_primes are available for use println!("Multithread {:?}",start_timer.elapsed() ); println!("found {} primes up to a value of {}",known_primes.len(),known_primes[&known_primes.len()-1]); // print!("{{"); for value in known_primes { print!("{}, ",value) }; print!("0 }}") }

 

on my computer my imperfect "start-finish blocks overlap what was I thinking that's not ideal code" finds 9,147,542 primes, up to a prime value of 162,894,161 in just a titch over 6 seconds.  Not bad for a 6 core computer built in 2013.  That's damn fast really. Running the same task on a single cpu takes 46.4 seconds, so rayon provides a 6.8x speedup on 6 cores!

Rayon is super fast, and (range_start..range_stop).into_par_iter().filter_map.(|var| {if function(var) {Some(otherfunction(var))} else {None}  }  ).collect() is a sweet sweet thing.  If you are not a programmer, a for loop is like a fireing squad bringing out one prisoner at a time vs. rust's  firing squad taking down seven in one go.   Rayon is polite too, my machine doesn't act like the cpu's are pegged 100% when the cpu's are actually pegged 100%... rayon respects other cpu tasks and is good at snatching free cycles.  Maybe "no memory garbage collection" plus apple's Mojave grand central dispach keeps the mouse and os acting buttery smooth.   **magical bonus points: the nine million results all seem to be in the right order, I wasn't expecting to be able to avoid a sort after multithreading a prime number search.  Rayon is beautiful for data parallelism and multi - threads.  

Rayon is winning me over to the rust side.  Its all about those great strides.

*a note for beginners like me about types, not keyboard typing:  Type systems just keep the 1's and 0's in computers organized. 0010000 could be a number 64, a "execute return from interupt" command, the letter 'a', or part of something bigger like a memory address or long variable that contains the entire digital contents of the library of congress.  There are more than one way to be organized and tidy, and many computer languages exist solely because someone wanted to find the worst way possible to solve this common but vexing computer problem.

** a differences test shows them to increase in order.   A pipe into mathematica confirms primality and set size.

PrintView Printer Friendly Version

EmailEmail Article to Friend

Reader Comments (1)

My cargo.toml file:
[package]
name = "prime2"
version = "0.1.0"
authors = ["dustandoud"]

[dependencies]
rayon = "1.0.1"

[profile.dev]
opt-level = 3

[profile.release]
opt-level = 3

July 13, 2018 | Registered CommenterDustan Doud

PostPost a New Comment

Enter your information below to add a new comment.

My response is on my own website »
Author Email (optional):
Author URL (optional):
Post:
 
Some HTML allowed: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <code> <em> <i> <strike> <strong>
« The Black and White Illustrated me | Main | Deficit of the Dead in Puerto Rico »