Tag: SAORI’

ファイル読み書きはどれくらい遅いのか(追記あり)

 - by Don

YAYAで測定

ファイルの読み書きは遅いというのは体感的に何となく知っているのですが、どのくらい遅いのか調べてみようと思いました。

実験で使用するSHIORIはYAYA。関数のFREADFWRITEをそれぞれ1,000,000回実行して掛かった時間を測定します。ループ自体に掛かる時間や代入処理に掛かる時間なども比較のために測定します。

ループだけの処理//2秒
{
  _n = 1000000

  _start = GETTIME[6]
  for _i = 0; _i < _n; _i++ {
    //何もしない
  }
  _end = GETTIME[6]

  '\0\s[0]\_qstart: ' + _start + '\nend: ' + _end
}

代入処理//4秒
{
  _n = 1000000

  _start = GETTIME[6]
  for _i = 0; _i < _n; _i++ {
    _hoge = _i //代入
  }
  _end = GETTIME[6]

  '\0\s[0]\_qstart: ' + _start + '\nend: ' + _end
}

読み//10秒
{
  _filename = 'xxx'
  _n = 1000000

  _start = GETTIME[6]
  if !FOPEN(_filename, 'r')
    return
  for _i = 0; _i < _n; _i++ {
    _line = FREAD(_filename) //読む
  }
  FCLOSE(_filename)
  _end = GETTIME[6]

  '\0\s[0]\_qstart: ' + _start + '\nend: ' + _end
}

書き//10秒
{
  _filename = 'xxx'
  _n = 1000000

  _start = GETTIME[6]
  if !FOPEN(_filename, 'w')
    return
  for _i = 0; _i < _n; _i++ {
    FWRITE(_filename, 'hoge') //書く
  }
  FCLOSE(_filename)
  _end = GETTIME[6]

  '\0\s[0]\_qstart: ' + _start + '\nend: ' + _end
}

ループだけでもカウンタ_iがインクリメントされるのでその処理時間が掛かっているように見受けられます(代入処理を加えるとちょうど2倍の時間になっています)。ファイルのオープン/クローズのオーバーヘッドの影響がこの例ではほぼ無視されてしまいますがそれでもそれなりに時間が掛かっているようです(ファイルの開け閉めを同じ回数だけ回すとさらに2倍くらいかかります)(←勘違い)

追記

やっぱりFOPEN/FCLOSEまで含めての実験が必要ですね。ということで

読み//202秒
{
  _filename = 'xxx'
  _n = 1000000

  _start = GETTIME[6]
  for _i = 0; _i < _n; _i++ {
    if !FOPEN(_filename, 'r')
      return
    _line = FREAD(_filename) //読む
    FCLOSE(_filename)
  }
  _end = GETTIME[6]

  '\0\s[0]\_qstart: ' + _start + '\nend: ' + _end
}
書き//1510秒?(100,000回ループの値を10倍しました)
{
  _filename = 'xxx'
  _n = 1000000

  _start = GETTIME[6]
  for _i = 0; _i < _n; _i++ {
    if !FOPEN(_filename, 'w')
      return
    FWRITE(_filename, 'hoge') //書く
    FCLOSE(_filename)
  }
  _end = GETTIME[6]

  '\0\s[0]\_qstart: ' + _start + '\nend: ' + _end
}

他のSHIORIとの比較

前回の里々での実験においてループ回数を揃えて並べれば、SHIORIの処理能力の比較ができそうな気がします。

*nop関数
:[開始](現在秒)(loop,loop_nop,1000000)
[終了](現在秒)#82秒

*set関数
:[開始](現在秒)(loop,loop_set,1000000)
[終了](現在秒)#138秒

@loop_nop
(nop,)

@loop_set
(set,hoge,)

遅いですね。びっくりです。

ついでに華和梨でも調べてみます。

# ループのみ(1秒)
sample1: \0\s[0]\_qstart: $(date %S)$(loop 1000000 "")\nend: $(date %S)\e

# エコー関数(6秒)
sample2: \0\s[0]\_qstart: $(date %S)$(loop 1000000 $(echo ""))\nend: $(date %S)\e

# 代入関数(8秒)
sample3: \0\s[0]\_qstart: $(date %S)$(loop 1000000 $(setstr foo bar))\nend: $(date %S)\e

ループ自体では関数呼び出し1回のみで他の関数呼び出しが無い分高速のようです。代入などの関数をコールすればそれなりの時間を要するみたいです。

まとめ

表にすると見やすいかもしれない。

処理内容(1,000,000回) 時間(秒)
YAYA ループのみ(for) 2
YAYA 代入 4
YAYA ファイル読み(FREAD) 10
YAYA ファイル書き(FWRITE) 10
YAYA ファイル読み(FOPEN,FREAD,FCLOSE) 202
YAYA ファイル書き(FOPEN,FWRITE,FCLOSE) 1510(?)
里々 何もしない関数(nop) 82
里々 代入関数(set) 138
華和梨 ループのみ 1
華和梨 エコー関数(echo) 6
華和梨 代入関数(setstr) 8

ファイル読み書きの遅さの検証のはずが里々の遅さにびっくりする結果となりました。ファイル読み書きが逆に高速に見えてしまいます。こんなはずでは。

複数のファイルを開け閉めするのはそれなりに時間がかかるようですが、1つのファイルに何万行読み書きしてもそれ自体はあまり時間はかからないようです。

でも実用上1,000,000回もループする処理なんて普通のゴースト開発ではまずあり得ないですね。

SAORI呼び出しはどれくらい遅いのか

 - by Don

里々で測定

内部関数 V.S. SAORI

SAORI呼び出しは遅いというのは体感的に何となく知っているのですが、どのくらい遅いのか調べてみようと思いました。

実験で使用するSHIORIは里々。内部関数のwhenとSAORIであるssu.dllのifをそれぞれ同じ回数実行して掛かった時間を測定します。里々で時間を取得するために(現在秒)を使います。本当はミリ秒まで見たいけど仕方ない。

*
:[開始](現在秒)(loop,loop_when,100000)
[終了](現在秒)#9秒

*
:[開始](現在秒)(loop,loop_if,100000)
[終了](現在秒)#17秒

@loop_when
(when,1,)

@loop_if
(if,1,)

環境にもよるのでしょうが100000回だとwhenで9秒、ifで17秒ということで大体2倍程度の違いが見られます。

ssu.dll V.S. YAYA as SAORI with ssu.aym

応答速度はSAORIにもよります。ssu.dllのsplitとssu.aymのsplitで比較してみます。

*
:[開始](現在秒)(loop,loop_split,30000)
[終了](現在秒)#6秒

*
:[開始](現在秒)(loop,loop_split_yaya,30000)
[終了](現在秒)#77秒

@loop_split
(nop,(split,))

@loop_split_yaya
(nop,(aya,split,))

nopが含まれているので正確ではないですが30000回だとssu.dllで6秒、ssu.aymで77秒と10倍近く違います。

10回程度のループ処理をYAYAに投げるくらいならssu.dllを10回呼び出してもさほど変わらないようです。

他に時間のかかることとの比較

HTTPリクエストやファイルの読み書きとの比較も面白そうですが、また今度。

2012年の抱負

 - by Don

あけましておめでとうございます。

3年くらい前に"今年こそはSAORIを作る"みたいなことを書いていて未だ達成できていないので、今年もそれでいこうと思います。

YAYAからPLUGINを呼び出す

 - by Don

SAORIみたいに呼ぶ

YAYAからSAORIを呼び出す関数(FUNCTIONEX)は大抵システム辞書(yaya_shiori3.dic)に書いてあります。

そこでPLUGINを呼び出す関数も書いてみました。

https://gist.github.com/1048890

はろーYAYAわーるど」のシステム辞書に追加する形で利用できます。

PLUGINは通常ユーザが実行する、もしくは![raiseplugin]などを使ってSSP経由でゴーストが呼び出すものですが、何らかの事情でゴーストに同梱してSHIORIから直接呼び出したい場合もあるかもしれません。usage.txtの例にある通り、SwissArmyKnifeなど多機能なPLUGINもありますし、ユーザがPLUGINを無効化していた場合などでもゴーストに同梱しておけばいつでも使えて安心です。(メジャーな機能を持つSAORIは各ゴーストに積むよりもPLUGINにしてみんなで利用しよう、という精神に反しますが。)

里々からPLUGINを呼び出したい場合は、satori.dll =(SAORI)=> yaya.dll =(PLUGIN)=> SAKNIFE.DLL といった具合にYAYA as SAORI経由で二段重ねで呼び出せます。

もちろん、SAORIのように単一機能を呼び出すだけの単純な構成のPLUGINに限られます。PLUGINはGHOSTと一緒で、常にSSPからイベントを受信しているので、通常は複雑な機能を実現する場合が多いです。

何故こんなものを

gomi.dllがバグってると聞いたので、SAORIでないとダメなのかなと思って書いてみました。でもやはりPLUGINは![raiseplugin]で利用した方がいいですね。