15
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

rayonでお手軽並列処理

Last updated at Posted at 2019-12-14

この記事はRustその3 Advent Calendar 2019 12/14の記事です。
並列処理ライブラリrayonの紹介です。

rayonとは?

rayonは、スレッドをいい感じに使って、非常に気軽に並列処理ができるライブラリです。

配列の各要素に対して並列処理: par_iter

最も手軽に利用できるのが、use rayon::prelude::*;だけですぐに利用できるpar_iterです。
配列の各要素に対して並列処理を行うことができます。iter()par_iter()に置き換えるだけで、配列操作の感覚で処理の並列化ができます!
par_iter()した後に使えるメソッドはここから見られます。

extern crate rayon;

use rayon::prelude::*;
let food_prices = [100, 120, 2000, 1840, 600, 100, 120, 2000];

let takeout_price = food_prices
    .par_iter()
    .map(|&i| (i as f32 * 1.08) as i32) // これ以降の処理が並列処理に!
    .reduce_with(|m, n| m + n)
    .unwrap();

println!("{}", takeout_price);

カスタムな並列処理

上記のpar_iter以外にも、自分でカスタマイズした並列処理を行うためのAPIが用意されています。

2つの並列処理: join

2つの処理の結果を利用したい場合、joinを使います。分割統治法を使うアルゴリズムのような、1つの大規模な処理をたくさんの小さな処理に分割できるケースで適用できます。

use rayon::join;

fn hell_fibonacci(x: u64) -> u64 {
    if x < 2 {
        return x;
    }
    let (prev, prevprev) = join(|| hell_fibonacci(x - 1), || hell_fibonacci(x - 2));
    prev + prevprev
}

println!("{}", hell_fibonacci(5));

任意の数の並列処理: scope

joinでは扱えない、任意の数の並列処理はscopeで行います。自由にタスクをspawnできます。

use rayon::scope;

use std::sync::atomic::{AtomicUsize, Ordering};
static COUNTER: AtomicUsize = AtomicUsize::new(0);

scope(|s| {
    s.spawn(move |_| {
        COUNTER.fetch_add(1, Ordering::SeqCst);
    });

    s.spawn(move |_| {
        COUNTER.fetch_add(2, Ordering::SeqCst);
    });

    s.spawn(move |_| {
        COUNTER.fetch_add(3, Ordering::SeqCst);
    });
});
println!("COUNT:{:?}", COUNTER);

ベンチマーク

リポジトリ内のベンチマーク に入っている階乗計算のベンチマークを、手元の環境(MacBook Pro Retina 13inch 4コア/8スレッド)で実行してみました。

test factorial::factorial_iterator  bench:  15,679,758 ns/iter (+/- 817,472)
test factorial::factorial_par_iter  bench:   2,262,074 ns/iter (+/- 153,986) 
test factorial::factorial_recursion bench:   4,060,433 ns/iter (+/- 394,378)
test factorial::factorial_join      bench:   2,129,283 ns/iter (+/- 190,471)

_par_iterが_iteratorの並列化に、_joinが_recursionの並列化に対応しています。
このベンチマークでは9999!を計算してますが、十分並列化による効果が出ているという印象です。

15
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
15
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?