2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

AppleScript ハンドラの高速化

Posted at

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

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

ところが、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)では
こうなりました。
0122_1.png
そりゃそうです。
「こんなループ、ハンドラの中でやらなきゃ遅いに決まってんだろ!」
と先輩から怒られる代物です。
#script object を使用したハンドラ処理

そこで試して頂きたいのが、
以前投稿した、 [script object を使用した高速化処理] (https://qiita.com/ginn_nezz/items/b7b1ad86f61d47bdf10d) です。

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

結果はこうなります。
0122_2.png

またもや1/10以下!

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

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

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

ぜひお試しください。

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?