試験運用中なLinux備忘録・旧記事

はてなダイアリーで公開していた2007年5月-2015年3月の記事を保存しています。

連結リストへのデータ追加にかかる方向/時間のテストを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

*1:リスト内の各データの型は自由に決められ、「G」はその型の名前が入ることを示す・C#言語でも同様だが「T」と書かれるようだ

*2:valac-CオプションによりC言語に変換したコードを見るとこれらが書かれている