AppleScript スクリプトバンドルの高速化


スクリプトバンドルでのループ処理

今回は、以前投稿した
AppleScript ハンドラの高速化
スクリプトバンドル
実践してみましょう。

以前と同じ条件で、
(1)1〜10,000をループさせて、
(2)ループ変数とリスト変数をハンドラへ渡し、
(3)ハンドラでループ変数を文字列化してリストに追加、
(4)ハンドラからリストを戻す。

の時間を計測します。

まずは
AppleScript 標準リストバージョン。

ライブラリとして以下を
「myLoop.scpt」で保存、
Script Librariesに入れます。

サンプルコード1
sample1
on do(i, theResult)
    set end of theResult to i as string
    return theResult
end do

メインのスクリプトバンドルは
以下で保存してください。
ファイル名は何でもいいです。

サンプルコード2
sample2
use framework "Foundation"
use scripting additions

set eDate to current application's NSDate's timeIntervalSinceReferenceDate()

set theResult to {}

repeat with i from 1 to 10000
    set theResult to script "myLoop"'s do(i, theResult)
end repeat

display alert ((((current application's NSDate's timeIntervalSinceReferenceDate()) - eDate) & "秒かかりました") as string)

theResult

結果は、

…ま、
遅いだろうとは思ってましたが、
4秒に手が届きそうな遅さと知って、
殺意が湧いてきました。

要するに、
Script Libraries のハンドラで
10,000回の受け渡しをやると
基本的に遅いのです。

script object のループ処理

では、
同じことを script object を介して
実行してみます。

同様に、
ライブラリとして以下を
「myLoop.scpt」で保存、
Script Librariesに入れます。

サンプルコード3
sample3
script theIterator
    property record : 0
end script

script theResult
    property record : {}
end script

on do(theIterator, theResult)
    set end of record of theResult to record of theIterator as string
    return theResult
end do

※後ほど改めて解説しますが、
 トップレベル(メインスレッド)にも受け手のハンドラ側にも
 script object の宣言が必要になります。

続いて、
メインのスクリプトバンドルは
以下で保存してください。
こちらもファイル名は何でもいいです。

サンプルコード4
sample4
use framework "Foundation"
use scripting additions

set eDate to current application's NSDate's timeIntervalSinceReferenceDate()

script theIterator
    property record : 0
end script

script theResult
    property record : {}
end script

set record of theResult to {}

repeat with i from 1 to 10000
    set record of theIterator to i
    set theResult to script "myLoop"'s do(theIterator, theResult)
end repeat

display alert ((((current application's NSDate's timeIntervalSinceReferenceDate()) - eDate) & "秒かかりました") as string)

record of theResult

結果は、

そのスピード、1/25!
とにかく気持ちいい。

ここまでくると、
AppleScript プログラムで使う変数は全て、
script object にしてしまうのがいいです。

script object 高速化の注意点

以前にも書いたことですが、
受け渡しは
script object を渡すこと。

ハンドラ部分を再度掲載しますが、
処理自体は
record of (スクリプト名)で行ない、
引数、戻り値は (スクリプト名)にしてください。
そうしないと高速化につながりません。

sample5
on do(theIterator, theResult)
    set end of record of theResult to record of theIterator as string
    return theResult
end do

さらにもう一点、
メインスレッド(トップレベル)側と
ライブラリ側とで、
script object の指定をそれぞれ行なうこと。

sample6
script theIterator
    property record : 0
end script

script theResult
    property record : {}
end script

この二点をおさえておけば、
必ず高速化します。
慣れるまで戸惑いもあるかもしれませんが、
試してみて損はありません。