Skip to content
Permalink
Browse files

Fearless Multi-Threading and Parallelism with Rust

  • Loading branch information...
ajmwagar committed Apr 15, 2019
1 parent 0cddece commit 0799df3bde3d2ad4d5f2f6988ff1a5a952977c4c
@@ -19,17 +19,31 @@ disableSitemap = false
disable404 = false
disableHugoGeneratorInject = true

[blackfriday]
hrefTargetBlank = true

[permalinks]
posts = "/posts/:year/:month/:title/"

[params]
dateform = "Jan 2, 2006"
dateformShort = "Jan 2"
dateformNum = "2006-01-02"
dateformNumTime = "2006-01-02 15:04 -0700"


disqusShortname = "averywagar"




# Metadata mostly used in document's head
description = "Homepage and blog by Avery Wagar"
keywords = "homepage, blog, science, informatics, development, programming"
images = [""]

homeSubtitle = "Software Developer"

# Directory name of your blog content (default is `content/posts`)
contentTypeName = "posts"
# Default theme "light" or "dark"
@@ -60,7 +74,7 @@ disableHugoGeneratorInject = true
title = "Avery Wagar"
subtitle = "Software Developer"
keywords = ""
copyright = "Avery Wagar 2019"
copyright = "Avery Wagar"
readOtherPosts = "Read other posts"

[languages.en.params.logo]
@@ -81,6 +95,9 @@ disableHugoGeneratorInject = true
# identifier = "showcase"
# name = "Showcase"
# url = "/showcase"
[taxonomies]
tag = "tags"
category = ""

# And you can even create generic menu
[menu]
@@ -1,16 +1,20 @@
---
title: "Avery Wagar"
title: "About"
date: 2019-04-14T02:42:30+01:00
draft: false
author: Avery Wagar
---

{{< image src="/d.png" alt="Avery Wagar" position="left" style="height:250px;">}}
{{< image src="/d.png" alt="Avery Wagar" position="left" style="height:250px; width: 250px; -webkit-border-radius: 50%; -moz-border-radius: 50%; -ms-border-radius: 50%; -o-border-radius: 50%; border-radius: 50%; ">}}

VR developer since 2016. Experience in Unity, C#, Java, JavaScript, Python, Rust.
__VR developer since 2016. Experience in Unity, C#, Java, JavaScript, Python, and Rust.__

I am a student at Ballard High School (BHS; class of 2021) in Seattle, Washington, studying computer science and digital filmmaking and exploring the intersection of both through virtual reality and immersive/360 video.
_I am Avery Wagar_, a student at Ballard High School (BHS; class of 2021) in Seattle, Washington, studying computer science and digital filmmaking and exploring the intersection of both through virtual reality and immersive/360 video.

I am the founder and president of BVR Club, BHS’s virtual reality club and was the first ninth-grader to enroll in AP computer science at BHS. I created AstroVR (formerly StarVR), a virtual reality astronomy simulator that won best overall engineering project at the 2017-18 Seattle Public Schools eighth grade district science and engineering fair. I am also the co-founder and lead developer of Outrigger, an email productivity application promoting inbox life balance, and a student representative on the Information Technology Advisory Committee for Seattle Public Schools.
I am the founder and president of [BVR Club][BVR_HOME], BHS’s virtual reality club and was the first ninth-grader to enroll in AP computer science at BHS. I created [AstroVR][ASTROVR_HOME] (formerly StarVR), a virtual reality astronomy simulator that won best overall engineering project at the 2017-18 Seattle Public Schools eighth grade district science and engineering fair. I am also the co-founder and lead developer of [Outrigger][OUTRIGGER_HOME], an email productivity application promoting inbox life balance, and a student representative on the Information Technology Advisory Committee for Seattle Public Schools.

I have participated in numerous hackathons across various technologies and taught software development to underrepresented high school students. When not in front of a computer programming or editing film, or immersed in VR, I enjoy film production, photography, cycling, drinking coffee, gathering around a campfire, and long walks with the family dog.

[BVR_HOME]: https://bvrclub.com
[ASTROVR_HOME]: https://ajmwagar.itch.io/astrovr
[OUTRIGGER_HOME]: https://outriggerapp.com
@@ -0,0 +1,209 @@
---
title: Fearless Multi-threading & Parallelism with Rust
author: Avery Wagar
date: 2019-04-15
draft: false
toc: false
tags:
- Rust
- Programming
- Multi-threading
- Concurrency
---

Multi-threading, Concurrency, and Parallelism are hard and can be scary. With problems like data-races and worrying about thread safety, it can be easy to stay away from them altogether. Luckily for us, Rust has our backs when it comes to thread safety and all the other perils that come our way when building Multi-threaded code. In-fact Rust's compiler will not let __compile__ code that has a potential data-race in it. Therefore we are free to write out code without fear.

## Multi-threading

There are multiple ways that Rust helps us prevent data-race and enforce thread safety.

### Arc & Mutex

One way that Rust provides is to use `Arc` and `Mutex` when sharing data across threads. For example, here we have an integer that we want multiple threads to mutate. We can protect the data and other threads by using a Mutex which ensures our data is not poisoned, more about that [here](https://doc.rust-lang.org/std/sync/struct.Mutex.html#poisoning).

```rust
// Import the required types
use std::sync::{Arc, Mutex};
use std::thread;
const N: usize = 10;
fn main() {
// Here we're using an Arc to share memory among threads,
// and the data inside the Arc is protected with a mutex.
let safe_data = Arc::new(Mutex::new(0));
println!("Data: {:?}", safe_data); // Mutex: { data: 0 }
// Create an array of thread handles
let handles = (0..N)
.into_iter()
.map(|_| {
let data = Arc::clone(&safe_data);
thread::spawn(move || {
// Unlock the mutex so the thread may mutate the data
// We unwrap() the return value to assert that we are not
// expecting threads to ever fail while holding the lock.
let mut data = data.lock().unwrap();
// Mutate the data
*data += 1;
// the lock is unlocked here when `data` goes out of scope.
})
})
.collect::<Vec<thread::JoinHandle<_>>>();
// Wait for threads to finish mutating safe_data
for thread in handles {
thread.join().unwrap();
}
// Print out mutated data
println!("Data: {:?}", safe_data); // Mutex: { data: 10 } or N
}
```

In the example above we safely mutate an integer across threads, this can be applied with larger data types, however, for event-based interaction across threads I recommend using an `MPSC` (Multi-Producer, Single Consumer) channel.

### MPSC Channels

`std::sync::mpsc` channels are a quick and safe way to share _events_ across threads.

For example, we can use the `mpsc` channels in a small banking program:

```rust
use std::sync::mpsc::channel;
use std::thread;
/// Transaction enum
enum Transaction {
Widthdrawl(f64),
Deposit(f64)
}
fn main() {
// set the number of customers
let n_customers = 10;
// Create a "customer" and a "banker"
let (customers, banker) = channel();
let handles = (0..n_customers).into_iter().map(|i| {
// Create another "customer"
let customer = customers.clone();
// Create the customer thread
let handle = thread::spawn(move || {
// Define Transaction
let trans_type = match i % 2 {
0 => Transaction::Deposit(i as f64 * 10.0),
_ => Transaction::Widthdrawl(i as f64 * 5.0)
};
// Send the Transaction
customer.send(trans_type).unwrap();
});
handle
}).collect::<Vec<thread::JoinHandle<_>>>();
// Wait for threads to finish
for handle in handles {
handle.join().unwrap()
}
// Create a bank thread
let bank = thread::spawn(move || {
// Create a value
let mut bank: f64 = 10000.0;
// Perform the transactions in order
banker.into_iter().for_each(|i| {
match i {
// Subtract for Widthdrawls
Transaction::Widthdrawl(amount) => {
bank = bank - amount;
},
// Add for deposits
Transaction::Deposit(amount) => {
bank = bank + amount;
},
}
println!("Bank value: {}", bank);
});
});
// Let the bank finish
bank.join().unwrap();
}
```

The output of the above program would look something like this:
```
Bank value: 10000
Bank value: 9995
Bank value: 10015
Bank value: 10000
Bank value: 9975
Bank value: 10035
Bank value: 10075
Bank value: 10040
Bank value: 10120
Bank value: 10075
```

As you can see `mpsc` channels are a powerful tool. Whether is sending events from a game loop to different threads, or high-frequency transactions, channels are a powerful tool when it comes to dealing with events and threads.


## Parallelism with Rayon

Now on to __Parallelism__. [Rayon](https://github.com/rayon-rs/rayon) is a Rust Library or "crate" that makes this dead simple.

Just add this to your `Cargo.toml`:

```toml
[dependencies]
rayon = "1.0"
```

And add this to your `src/main.rs`:

```rust
use rayon::prelude::*;
```

Rayon comes with a strong parallel iterator API. That means that most of the time all you need to do to achieve __Parallelism__ is replacing your `.iter()` calls with `.par_iter()` and your `.into_iter()` calls with `.into_par_iter()`.

For example here is a Factorial function that is __not__ executing in parallel:

```rust
/// Compute the Factorial using a plain iterator.
fn factorial(n: u32) -> BigUint {
(1..n + 1)
.into_iter()
.map(BigUint::from)
.fold(BigUint::one(), Mul::mul)
}
```

And this is a Factorial function that __is__ executing in parallel:

```rust
/// Compute the Factorial using a parallel iterator.
fn factorial(n: u32) -> BigUint {
(1..n + 1)
.into_par_iter() // This line is different
.map(BigUint::from)
.reduce_with(Mul::mul).unwrap() // And this line is different
}
```

We only need to change __2 lines__ to change our function from sequential to parallel. There are plenty more examples of using Rayon in the `/rayon-demo` folder in their [git repository](https://github.com/rayon-rs/rayon/tree/master/rayon-demo).

## Conclusion

Rust, if applied in the right way, makes Multi-threading and Parallelism a breeze. Whether you use `Arcs` and `Mutexes` or `MPSC` channels, hopefully, you can proceed without fear when you have the urge to add Parallelism or Multi-threading into your next Rust project.
@@ -4,6 +4,11 @@ author: Avery Wagar
date: 2017-10-23T13:35:00+01:00
draft: false
toc: false
tags:
- Ge2
- esports
- drones
- virtual-reality
---

This weekend Seattle was home the second annual edition of GE2.
@@ -4,6 +4,9 @@ author: Avery Wagar
date: 2018-02-02T13:35:00+01:00
draft: false
toc: false
tags:
- vim
- devtools
---

Welcome back my fellow Vim enthusiasts! Today we will be discussing a few shortcuts you can add to your __.vimrc__!

0 comments on commit 0799df3

Please sign in to comment.
You can’t perform that action at this time.