AppleScript ハンドラの高速化


ハンドラのデータ受け渡し

構造化プログラミングを行なう上で、
サブルーチン(ハンドラ)は
プログラムの見通しを良くするために必要だと言われます。

ところが、AppleScript はハンドラでのデータ受け渡しがとても遅く、
繰り返しハンドラを呼び出すとさらに遅くなります。

それはそれで、実行速度は工夫次第で何とかするもの、
と思い込んでましたが、それにしても遅いです。

本当は、工夫よりも知識と探求心なんじゃないか、
と思います。

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

サンプルコード1
sample1
use framework "Foundation"
use scripting additions

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

property theResult : {}

set theResult to {}

repeat with i from 1 to 10000
    set theResult to my theLoop(i)
end repeat

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

----------------------------------※Script Librariesハンドラを想定

on theLoop(i)
    set end of theResult to i as string
    return theResult
end theLoop

私のMacBook Pro(os10.14.6/2.2GHz Intel Core i7)では
こうなりました。

そりゃそうです。
「こんなループ、ハンドラの中でやらなきゃ遅いに決まってんだろ!」
と先輩から怒られる代物です。

script object を使用したハンドラ処理

そこで試して頂きたいのが、
以前投稿した、 script object を使用した高速化処理 です。

repeat 文のループ変数、及びリスト変数を script object として設定、
script object 自体を引数と戻り値にしています。

サンプルコード2
sample2
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 theIterator to 0
set record of theResult to {}

repeat with i from 1 to 10000
    set record of theIterator to i
    set theResult to my theLoop(theIterator)
end repeat

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

----------------------------------※Script Librariesハンドラを想定

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

結果はこうなります。

またもや1/10以下!

どうも AppleScript は変数の処理に負荷が掛かっており、
プログラムの中で使う変数を全て script object にすることで
なぜか負荷が軽減されるようです。

特にハンドラのデータ受け渡しを
script object にしてしまうことがポイント。

デメリットとしては
センテンスがかなり冗長になってしまうので
プログラムの見通しが悪くなりそうですが、
Cocoa フレームワーク呼び出しも相当なものなので、
要は「慣れ」だと思います。

ぜひお試しください。