Proxomitronは十分に速いから、「速度重視でフィルタを最適化する必要はない」と言われる事があります。
それはそれで1つの考え方ですが、それでも速度を上げる余地があるのなら、高速化してみたいと思いませんか?
$URLを検索表現の先頭に置くと、Proxomitronは1バイトずつURLテストします。
これは非常に効率が悪く、$URL を何らかのマッチングパターンの後ろに置いた方が速くなります。
以下の2つのフィルタを比べてみて下さい。
[Patterns] Name = "$URL test1" Active = TRUE Limit = 256 Match = "$URL(http://www.Shonen.Knife.com/)" "It is a test." Replace = "Proxomitron"$URL test2
[Patterns] Name = "$URL test2" Active = TRUE Limit = 256 Match = "It is a test." "$URL(http://www.Shonen.Knife.com/)" Replace = "Proxomitron"
前者は$URLを検索表現の先頭に置いたフィルタ、後者は$URLを検索表現の後部に置いたフィルタです。
以下のソースを使って、それぞれのフィルタをテストウインドウで [プロファイル] してみてください。
(テストウインドウでは URL = http://www.Shonen.Knife.com/Naoko/Michie/Atsuko/kappa.ex.cgi?jackalope
として扱われます。)
「平均時間」の項で、各フィルタの平均速度を確認できます。
平均速度には誤差があり、測るタイミングによって平均速度が変わりますので、10回ほど測って平均値を取ると確実です。
It is a test. It is a test. It is a test. It is a test. It is a test. It is a test. It is a test. It is a test. It is a test. It is a test.
私の環境では、それぞれ10回ずつ測った平均値は以下のようになりました。
ミリ秒とは「1000分の1秒」を指します。
ですので、ミリ秒から秒に直すと、非常に小さな値になっちゃいますね。
ただし、この「1バイトずつURLテスト」は探す範囲が多ければ多いほど影響が出てきます。
今回は短いソースでテストしましたが、長いソースになるほど速度差が顕著になるはずです。
試しに、「テスト内容とは全く関係のないソース」を使ってそれぞれのフィルタをテストしてみてください。
test2 は素早く終えますが、test1 はかなりの時間をかけてマッチしないはずです。
この事を踏まえると、$URLは何らかのマッチングパターンの後に置いた方が良いでしょう。
$STOPを使うと、「$STOPを実行したフィルタは2度と呼ばれない」ため、高速化します。
\kを使うと、「現在の接続を切断する = 検索対象がなくなる = 全フィルタがマッチしなくなる」ため、高速化します。
(もちろん、「以降のデータをダウンロードしなくてよい」という通信的な意味合いもあります。)
以下の2つのフィルタを比べてみて下さい。
[Patterns] Name = "Jump to abc.com test1" Active = TRUE Limit = 256 Match = "<a\s[^>]++href=$AV((http://abc.com/*)\0)" Replace = "<meta http-equiv="Refresh" content="0; url=\0" />"Jump to abc.com test2
[Patterns] Name = "Jump to abc.com test2" Active = TRUE Limit = 256 Match = "<a\s[^>]++href=$AV((http://abc.com/*a)\0)$STOP()" Replace = "\k<meta http-equiv="Refresh" content="0; url=\0" />"
a要素に http://abc.com/
のURLを見つけると、meta要素で該当URLにジャンプさせるフィルタです。
前者は $STOP, \k なしで、後者は $STOP, \k を使用しています。
以下のhtmlソースを使って、それぞれのフィルタをテストウインドウで [プロファイル] してみてください。
<a
href=
"http://abc.com/test.html"
>
It is a test.</a>
<a
href=
"http://abc.com/test.html"
>
It is a test.</a>
<a
href=
"http://abc.com/test.html"
>
It is a test.</a>
<a
href=
"http://abc.com/test.html"
>
It is a test.</a>
<a
href=
"http://abc.com/test.html"
>
It is a test.</a>
<a
href=
"http://abc.com/test.html"
>
It is a test.</a>
<a
href=
"http://abc.com/test.html"
>
It is a test.</a>
<a
href=
"http://abc.com/test.html"
>
It is a test.</a>
<a
href=
"http://abc.com/test.html"
>
It is a test.</a>
<a
href=
"http://abc.com/test.html"
>
It is a test.</a>
私の環境では、それぞれ10回ずつ測った平均値は以下のようになりました。
約4倍の差ですね。
理屈上は、マッチ回数が多いほど差が開くはずなので、$STOP, \k を利用する価値は高いと思います。
# 「Jump to abc.com test2」のテスト中に "0ミリ秒" の結果が返ってきたことがあると思いますが、それはProxomitronで測れないほどに速いという意味です。
実際に、0秒でマッチしているわけではありません。
Boundsはフィルタを見やすくしますが、代わりに速度を犠牲にしています。
「Boundsで1度テストしてから、検索表現でテストする」という二度手間になっているので、速度的には不利になってしまうのです。
以下の2つのフィルタを比べてみてください。
[Patterns] Name = "Replace img test1" Active = TRUE Bounds = "<img\s[^>]+>" Limit = 256 Match = "*src=$AV(test.png)*" Replace = "Replaced"Replace img test2
[Patterns] Name = "Replace img test2" Active = TRUE Limit = 256 Match = "<img\s[^>]++src=$AV(test.png)[^>]+>" Replace = "Replaced"
前者はBoundsを使ったフィルタ。後者はBoundsなしのフィルタです。
以下のhtmlソースを使って、それぞれのフィルタをテストウインドウで [プロファイル] してみてください。
<img
width=
'512'
height='64'
src='test.png'
alt='test'
/>
<img
width=
'512'
height='64'
src='test.png'
alt='test'
/>
<img
width=
'512'
height='64'
src='test.png'
alt='test'
/>
<img
width=
'512'
height='64'
src='test.png'
alt='test'
/>
<img
width=
'512'
height='64'
src='test.png'
alt='test'
/>
<img
width=
'512'
height='64'
src='test.png'
alt='test'
/>
<img
width=
'512'
height='64'
src='test.png'
alt='test'
/>
<img
width=
'512'
height='64'
src='test.png'
alt='test'
/>
<img
width=
'512'
height='64'
src='test.png'
alt='test'
/>
<img
width=
'512'
height='64'
src='test.png'
alt='test'
/>
私の環境では、それぞれ10回ずつ測った平均値は以下のようになりました。
約1.3倍の速度差ですね。
このぐらいの違いであれば、「見た目を重視してBoundsを使う」という考え方も有りだと思います。
# Boundsと同様の理由で、AND関数, ダブルアンバサンド も遅くなります。
「アスタリスク は ?++
と同義。よって、?+
は *
より速い。」 という結果になるかと思いきや、全く逆の結果になりました。
以下の2つのフィルタを比べてみてください。
[Patterns] Name = "wildcard test1" Active = TRUE Limit = 32767 Match = "*" Replace = "Matched"wildcard test2
[Patterns] Name = "wildcard test2" Active = TRUE Limit = 32767 Match = "?+" Replace = "Matched"
前者は *
を使ったフィルタ。後者は ?+
を使ったフィルタです。
適当な 30000バイト の文字列を使って、それぞれのフィルタをテストウインドウで [プロファイル] してみてください。
私の環境では、それぞれ10回ずつ測った平均値は以下のようになりました。
計測不能なほどの違いがあるようです。
あまり、?+
を使わない方が良さそうですが、状況に応じて使わざるを得ない事もあるでしょう。
消費する文字数が少ないほど速度差は少なくなるので、臨機応変に使い分けて下さい。
OR関数は内部のマッチングパターンが短いと遅くなることがあります。
その場合は、OR関数の内部パターンにそれぞれ後述の文字列をセットすると、高速化を期待できます。
以下の2つのフィルタを比べてみてください。
[Patterns] Name = "or function test1" Active = TRUE Limit = 256 Match = "(h|)eight" Replace = "Replaced"or function test2
[Patterns] Name = "or function test2" Active = TRUE Limit = 256 Match = "height|eight" Replace = "Replaced"
前者はOR関数の「something or nothing」を使ったフィルタ。後者は "eight" を含めたOR関数のフィルタです。
以下のソースを使って、それぞれのフィルタをテストウインドウで [プロファイル] してみてください。
Howard Hawks have to examine the height of Mt. Kanchenjunga at eight. Howard Hawks have to examine the height of Mt. Kanchenjunga at eight. Howard Hawks have to examine the height of Mt. Kanchenjunga at eight. Howard Hawks have to examine the height of Mt. Kanchenjunga at eight. Howard Hawks have to examine the height of Mt. Kanchenjunga at eight. Howard Hawks have to examine the height of Mt. Kanchenjunga at eight. Howard Hawks have to examine the height of Mt. Kanchenjunga at eight. Howard Hawks have to examine the height of Mt. Kanchenjunga at eight. Howard Hawks have to examine the height of Mt. Kanchenjunga at eight. Howard Hawks have to examine the height of Mt. Kanchenjunga at eight.
私の環境では、それぞれ10回ずつ測った平均値は以下のようになりました。
約10倍の速度差ですね。
これだけ違いがあれば、後述の文字列 (eight) をOR関数の内部に含める価値はありそうです。
比較したフィルタから想像できるように、これは (h|)
に原因があります。
なぜなら、ソースに含まれている "h" の数が多ければ多いほど、速度差が顕著になるからです。
試しに、hhhhhhhhhh...
と連続した "h" をソースに含めてテストしてみてください。
test2 はそれほど遅くなりませんが、test1 は目に見えて遅くなります。
2つのフィルタの作業プロセスを追ってみると以下のようになります。
or function test1見て分かるように、後者の方がプロセスが1つ少なくなります。
ここからは私の想像ですが、このプロセスが少ないことが影響しているのではないかと思います。
経験上、OR関数の内部に短いパターンがあった時には、この例題のように遅くなります。
逆に見れば、長いパターンであれば遅くならないので、OR関数の内部には程々に長いパターンを入れるようにした方が良いかと思います。