連結リストへのデータ追加にかかる方向/時間のテストをVala言語に移植
「GLibで連結リスト(リスト構造)にデータを追加する方向とその時間について」のテストをVala言語に移植してみた。
言語的にはC#言語に近いので「リストへのデータ追加にかかる方向/時間のテストをC#言語に移植」のコードに近いものの、実際にはC言語のGLibが使用されるため、扱い自体はGLib的なものとなっている。
メモ
- リストは単方向がSList<G>*1オブジェクト、双方向がList<G>オブジェクトで、どちらも「GLib」の名前空間にあるため、「using GLib;」を記述するとC#言語と同じ感覚で作成できる
- リストの先頭からデータを追加するのにはprepend()、末尾に追加するのにはappend()が利用可能
- GTimerはTimerというオブジェクトとして使用するが、使い方はC言語のGLibと同じ
- 条件シンボルはバージョン0.7.2の時点ではサポートしていて-D [シンボル名]で定義できるが、条件によってエラーとしたいところで「#error」を記述してもこれを処理できずに文法エラー「error: syntax error, invalid preprocessing directive」となる
- C言語のときに記述していた後始末処理(g_slist_free()とg_timer_destroy())はValaではreturn文のところで自動的に実行される*2
データを逆順にして手前から追加するものと末尾にそのまま追加するものとを比較するコード
[任意]ファイル名: slist_bench.vala
using GLib; /* * リスト構造へデータを追加するのにかかる時間を * 先頭に追加するのと末尾に追加するのとでそれぞれ測定する * * 先頭に追加するバージョン: * valac -D PREPEND slist_bench.vala -o slist_bench_prepend * 末尾に追加するバージョン: * valac -D APPEND slist_bench.vala -o slist_bench_append * それぞれ-d:VERBOSEを付けると各データを表示する * valac -D VERBOSE -D PREPEND slist_bench.vala -o slist_bench_prepend_verbose * valac -D VERBOSE -D APPEND slist_bench.vala -o slist_bench_append_verbose */ /* バージョン0.7.2の時点では「#error」を処理できない #if PREPEND && APPEND # error "PREPENDとAPPENDの両方を定義することはできません" #endif #if ! PREPEND && ! APPEND # error "PREPENDとAPPENDのいずれかを定義する必要があります" #endif */ namespace SListBench { class MainClass { public const int cnt = 1000; #if VERBOSE public static void display_data (int data) { print ("%d\n", data); } #endif public static int main (string[] args) { SList<int> list = new SList<int> (); /* 山括弧で型指定・内容は空に初期化される */ /* 開始 */ GLib.Timer t = new Timer (); /* タイマー生成と同時に計測開始 */ #if PREPEND /* 先頭に追加する場合・データは逆順に入れる */ for (int i = cnt - 1; i > -1; i--) /* 本来の順番で入れるものとする */ list.prepend (i); #else # if APPEND /* 末尾に追加する場合 */ for (int i = 0; i < cnt; i++) list.append (i); # endif #endif /* 停止 */ /* 停止後の再開はcontinue()、最初から開始し直すにはstart() */ t.stop (); #if VERBOSE /* 内容を表示 */ list.foreach ((Func) display_data); #endif /* 計測した経過時間を表示 */ print ("elapsed time: %.5f\n", t.elapsed ()); return 0; } } }
データをそのままの順番で追加後リストを逆順にするものと末尾にそのまま追加するものとを比較するコード
[任意]ファイル名: slist_bench2.vala
using GLib; /* * リスト構造へデータを追加するのにかかる時間を * 先頭に追加するのと末尾に追加するのとでそれぞれ測定する * * 先頭に追加するバージョン: * valac -D PREPEND slist_bench2.vala -o slist_bench2_prepend * 末尾に追加するバージョン: * valac -D APPEND slist_bench2.vala -o slist_bench2_append * それぞれ-d:VERBOSEを付けると各データを表示する * valac -D VERBOSE -D PREPEND slist_bench2.vala -o slist_bench2_prepend_verbose * valac -D VERBOSE -D APPEND slist_bench2.vala -o slist_bench2_append_verbose */ /* バージョン0.7.2の時点では「#error」を処理できない #if PREPEND && APPEND # error "PREPENDとAPPENDの両方を定義することはできません" #endif #if ! PREPEND && ! APPEND # error "PREPENDとAPPENDのいずれかを定義する必要があります" #endif */ namespace SListBench2 { class MainClass { public const int cnt = 1000; #if VERBOSE public static void display_data (int data) { print ("%d\n", data); } #endif public static int main (string[] args) { SList<int> list = new SList<int> (); /* 山括弧で型指定・内容は空に初期化される */ /* 開始 */ GLib.Timer t = new Timer (); /* タイマー生成と同時に計測開始 */ #if PREPEND /* 先頭に追加する場合・データは逆順に入れる */ for (int i = 0; i < cnt; i++) /* 本来の順番で入れるものとする */ list.prepend (i); /* 「逆順の逆順」にして方向を戻す */ list.reverse (); #else # if APPEND /* 末尾に追加する場合 */ for (int i = 0; i < cnt; i++) list.append (i); # endif #endif /* 停止 */ /* 停止後の再開はcontinue()、最初から開始し直すにはstart() */ t.stop (); #if VERBOSE /* 内容を表示 */ list.foreach ((Func) display_data); #endif /* 計測した経過時間を表示 */ print ("elapsed time: %.5f\n", t.elapsed ()); return 0; } } }
結果
動作結果はもちろんC言語のGLibと同じく、先頭からデータを追加したほうが高速に動作した。
$ ./slist_bench_prepend elapsed time: 0.00021 $ ./slist_bench_append elapsed time: 0.00227
動作速度については、ネイティブコードとしてビルドできるValaの特性により、C言語で直接書いたときと同じようなレベルとなっている。
2つ目のコードの実行時間については、C言語のときと同様に(逆順にする処理がそれほど重くないのか)1つ目のコードのときと大きな差が出なかったため、結果は省略。
関連記事:
使用したバージョン:
- Vala 0.7.2
- GLib 2.20.1