LoginSignup
13
10

More than 5 years have passed since last update.

rust 動的ディスパッチと静的ディスパッチの調査

Last updated at Posted at 2018-08-04

rust 動的ディスパッチと静的ディスパッチの調査

環境

rustc 1.27.1

概要

動的ディスパッチと静的ディスパッチってどっちが速いの?って思ったから検証してみました。
検証自体は、コンパイラの事詳しくないので正直ガバガバだと思いますが、rustのいい練習になったので記事にします。

動的ディスパッチ

動的ディスパッチの特徴を下記に記します。

  • コードが膨張しないが低速な仮想関数の呼び出しが必要
  • 正確な型は実行時になって初めて判明する
  • インライン化(コンパイラによる最適化手法)ができない

詳しく知りたい人は、同じくrustのチュートリアルページにある、トレイトオブジェクトのページを見てください。
トレイトオブジェクト

静的ディスパッチ

静的ディスパッチの特徴を下記に記します。

  • 呼び出される関数はコンパイル時に分かっている
  • インライン化可能
  • 同じ関数をそれぞれの型毎に幾つもコピーするためバイナリが膨張する

詳しく知りたい人は、同じくrustのチュートリアルページにある、トレイトオブジェクトのページを見てください。
トレイトオブジェクト

プログラムを組む1

クロージャを作成し、それを動的ディスパッチと静的ディスパッチの2通りの方法で呼び出し、時間を計測してみます。

端末で入力するバージョン(rust)
fn main(){
    // クロージャの作成
    let add_one = |x: i32| x + 1;

    loop{
        println!("試行回数を入力してください");

        let mut  trial_count =  String::new();
        io::stdin().read_line(&mut trial_count)
                .expect("端末からの読み取りに失敗");

        let trial_count: u64 = match trial_count.trim().parse(){
            Ok(num) => num,
            Err(_) => continue,
        };
        println!("{}回ループさせます", trial_count);

        // 静的ディスパッチ
        fn static_fanc<F>(some_closure: F) -> i32
            where F : Fn(i32) -> i32 {
            some_closure(1)
        }

        let start = Instant::now();
        for  _ in 0..trial_count{
            static_fanc(add_one);
        }
        println!("静的なディスパッチ:{:?}", start.elapsed());

        // 動的ディスパッチ
        fn dynamic_fanc(some_closure: &Fn(i32) -> i32) -> i32{
            some_closure(1)
        }

        let start = Instant::now();
        for  _ in 0..trial_count {
            dynamic_fanc(&add_one);
        }
        println!("動的ディスパッチ:{:?}", start.elapsed());
    }
}

以下は、10000と入力した例

出力
試行回数を入力してください
10000
10000回ループさせます
静的なディスパッチ:Duration { secs: 0, nanos: 1666373 }
動的ディスパッチ:Duration { secs: 0, nanos: 1439735 }

プログラムを組む2

わかりにくいので、csvにしてグラフにすることにしました。
試行回数は、とりあえず5万回。

csvを出力するバージョン(rust)
use std::time::{Instant};
use std::io::prelude::*;
use std::fs::File;

fn main(){
    let s = format!("rust.csv");
    let mut buffer = File::create(s).unwrap();

    // クロージャの作成
    let add_one = |x: i32| x + 1;

    for trial_count in 1..50000{

        // 静的ディスパッチ
        fn static_fanc<F>(some_closure: F) -> i32
            where F : Fn(i32) -> i32 {
            some_closure(1)
        }

        let start = Instant::now();
        for  _ in 0..trial_count {
            static_fanc(add_one);
        }
        let static_time = start.elapsed();

        // 動的ディスパッチ
        fn dynamic_fanc(some_closure: &Fn(i32) -> i32) -> i32{
            some_closure(1)
        }

        let start = Instant::now();
        for  _ in 0..trial_count {
            dynamic_fanc(&add_one);
        }
        let dynamic_time = start.elapsed();

        if trial_count % 1000  == 0 {
            write!(buffer, "{}, {}, {}\n", 
                        trial_count, 
                        static_time.subsec_nanos() / 1_000,
                        dynamic_time.subsec_nanos() / 1_000).unwrap();
        }
    }
}

次に、pythonを使います。

グラフ描画(python)
import csv
import numpy as np
import matplotlib.pyplot as plt

try:
    with open("./rust.csv", 'rt') as fin:
        reader = csv.reader(fin)
        trial_count = [i[0] for i in reader]; fin.seek(0)
        static_time = [i[1] for i in reader]; fin.seek(0)
        dynamic_time = [i[2] for i in reader]
except:
    print("エラー発生。プログラム終了。")
    sys.exit()

# 描画範囲の指定
print(trial_count)
print(static_time)

x = list(map(int, trial_count))
y1 =list(map(int, static_time))
y2 = list(map(int, dynamic_time))

# グラフ描画設定
plt.plot(x, y1, color="b", label="static")
plt.plot(x, y2, color="r", label="dynamic")
plt.ylabel("time(micro)") 
plt.xlabel("trial_count")
plt.title('static & dynamic')

# ラベルの描画
plt.legend()
# グラフの描画実行
plt.show()

グラフの表示

上記プログラムで作成したグラフを以下に掲載します。
1回目
figure_1-1.png
2回目
figure_1-2.png
3回目
figure_1-3.png

3つのグラフに規則性が見られません。
なんか、凄い跳ね上がってる所が多々あるぐらいです。
単純なプログラムでは、あまり変わらないということでしょうか。

13
10
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
13
10