Apple Event: May 7th at 7 am PT

Looks like no one’s replied in a while. To start the conversation again, simply ask a new question.

Making applescript run faster...

I am doing alot of Numbers scripting right now and it runs fine (with a bit of help from some of you). But some people have asked if I can make them run faster. Alot of us come from writting VBA in Excel on windoze, wehre a fairly good macro can run in under a second, doing lots of code and data manipulation. The same thing in Applescript takes ten or more times longer to run.

Not asking for specific items, I am sure that there are loads of web pages, I just don't seem to be able to find them in my searches. Do hints from system 7 apply to OSX?

Thanks alot in advance,
Jason

Power Mac Dual 2.0 G5, Mac OS X (10.5.1)

Posted on Jan 23, 2009 7:18 AM

Reply
Question marked as Best reply

Posted on Jan 23, 2009 10:45 AM

Camelot wrote:
When it comes to performance tuning, though, the same rules apply in AppleScript as in any other language - it requires profiling to identify which areas are slow and therefore where to concentrate your resources.


Ditto that. It's pointless trying to optimise until you know where the bottlenecks are. In your script? In the application? In the cross-process communication?


It's also worth remembering that AppleScript is a global, system-wide language and, as such, it has to be all things to all applications. Contrast this with VBA which is highly optimized for specific applications and you can see why a similar VBA script might be faster, but with some tuning you should be able to get close.


I'd disagree with this statement for a couple of reasons:

1. The AppleScript language itself is dog slow compared to most any other general purpose scripting language you care to mention. (To give an idea: these days I do all my non-trivial automation scripts using Python+appscript. Python's hardly renowned as a speed demon itself, but I still reckon it's at least 10x faster for the non-application stuff.) That said, this is only a factor if your script is doing a large amount of data munging itself; if all it does is control other processes then AS's own slowness is unlikely to be the main bottleneck.

2. VBA and AppleScript communicate with Excel via very different APIs that likely have very different performance characteristics. (That's a polite way of saying that Excel's Apple event API is almost certainly significantly slower than its VBA API.) Both ultimately operate on Excel's low-level Automation API, I'm going to guess that the VBA API is a more natural fit and thus has lower overheads. Apple events are kinda weird and applications usually have to do a fair bit of work to map them to their internals.

There may be other factors as well, but those two are the ones to look at first.
7 replies
Question marked as Best reply

Jan 23, 2009 10:45 AM in response to Camelot

Camelot wrote:
When it comes to performance tuning, though, the same rules apply in AppleScript as in any other language - it requires profiling to identify which areas are slow and therefore where to concentrate your resources.


Ditto that. It's pointless trying to optimise until you know where the bottlenecks are. In your script? In the application? In the cross-process communication?


It's also worth remembering that AppleScript is a global, system-wide language and, as such, it has to be all things to all applications. Contrast this with VBA which is highly optimized for specific applications and you can see why a similar VBA script might be faster, but with some tuning you should be able to get close.


I'd disagree with this statement for a couple of reasons:

1. The AppleScript language itself is dog slow compared to most any other general purpose scripting language you care to mention. (To give an idea: these days I do all my non-trivial automation scripts using Python+appscript. Python's hardly renowned as a speed demon itself, but I still reckon it's at least 10x faster for the non-application stuff.) That said, this is only a factor if your script is doing a large amount of data munging itself; if all it does is control other processes then AS's own slowness is unlikely to be the main bottleneck.

2. VBA and AppleScript communicate with Excel via very different APIs that likely have very different performance characteristics. (That's a polite way of saying that Excel's Apple event API is almost certainly significantly slower than its VBA API.) Both ultimately operate on Excel's low-level Automation API, I'm going to guess that the VBA API is a more natural fit and thus has lower overheads. Apple events are kinda weird and applications usually have to do a fair bit of work to map them to their internals.

There may be other factors as well, but those two are the ones to look at first.

Jan 23, 2009 9:41 AM in response to jaxjason

A lot of things from System 7 no longer apply, but some of them do, especially when dealing with loops and lists (arrays).

When it comes to performance tuning, though, the same rules apply in AppleScript as in any other language - it requires profiling to identify which areas are slow and therefore where to concentrate your resources.

It's also worth remembering that AppleScript is a global, system-wide language and, as such, it has to be all things to all applications. Contrast this with VBA which is highly optimized for specific applications and you can see why a similar VBA script might be faster, but with some tuning you should be able to get close.

Jan 23, 2009 1:00 PM in response to hhas

I'd disagree with this statement for a couple of reasons:


Au contraire. You appear to agree with me.

... I'm going to guess that the VBA API is a more natural fit and thus has lower overheads. Apple events are kinda weird and applications usually have to do a fair bit of work to map them to their internals.


This is the same thing I said, just using different words.

VBA for Excel, was written specifically for Excel., based around features that Excel has, and without any overhead for things that Excel does not support.
AppleScript, on the other hand, can do anything, anywhere and therefore is much more general-purpose. Consequently it doesn't have the focussed hooks and syntax that VBA does.

I think we're both saying the same thing here. 🙂

Jan 23, 2009 1:39 PM in response to Camelot

I do have experience with excel and VBA. Its my job. And I do have to disagree a little bit. It does work through the whole system to some degree. It isn't at the system level (like C might be considered), but I can interact with any program that has VBA interaction written in, just like Scriptable apps on a Mac open up for Applescript, but can be used through GUI scripts if they are not.

was written specifically for Excel.


no way. The Vb editor is actually a standalone program. VBA is a scripting type language written for the entire office platform, and beyond. The only difference is in the VB editor. If your writting inside the Word VBE, you do not have to explicitly create a word object. But I can use data from word, activate Excel and write/run my code exactly as if I was in Excel VBE, just have to create the excel object link (and reference for excels VBA "library" or "dictionary").

Which is why I did find it a little disappointing that Applecript runs so slow. Its not that different from VBA in essence, just that the editor is a free standing program.

I am really looking for anywhere that the "best practices" are talked about.

For example:in VBA, you don't normally want to interact with a full worksheet line by line, cell by cell. If you can pull it into memory as an array, you can work thorugh an entire sheet of data in less than 1 second. then drop it back in to the original range again. Where it might take minutes to work through by cells individually.

Or you should set the following code to stop Excel trying to update the screen as you amek changes. Prevents the calculations too.
Application.ScreenUpdating = False


Thanks for your help so far. I know that part about tracking down the slower parts of your code (although I can only find a way of recording whole seconds, used to decimal seconds when timing my procedures). I really am trying to find those little secrets about how to get it to speed up by using ... etc...

Thanks alot everyone... hope to hear alot more stuff.
Jason

Jan 23, 2009 3:46 PM in response to jaxjason

Hello Jason,

Some tips.

• When processing (large) list, define the list as property and use reference to that property in referencing to list's item. This will yield remarkable performance improvement (60 - 80 times faster as far as I can tell).

E.g. 1 Given -

--CODE1 (blooming slow)
set xx to {}
repeat with i from 1 to 1000
set end of xx to i
end repeat
set yy to {}
repeat with i from 1 to 1000
set end of yy to (xx's item i) * -1
end repeat
return yy
--END OF CODE1

--CODE1A (fast)
property xx : {}
property yy : {}

repeat with i from 1 to 1000
set end of my xx to i -- # note the usage of "my"
end repeat
repeat with i from 1 to 1000
set end of my yy to (my xx's item i) * -1 -- # idem.
end repeat
return my yy's contents
--END OF CODE1A

--CODE1B (fast and well-behaved)
main()
on main()
script o
property xx : {}
property yy : {}

repeat with i from 1 to 1000
set end of my xx to i -- # note the usage of "my" (or "o's")
end repeat
repeat with i from 1 to 1000
set end of my yy to (my xx's item i) * -1 -- # idem.
end repeat
return my yy's contents -- # return its contents, not reference
end script
tell o to run
end main
--END OF CODE1B

CODE1A and CODE1B are much faster than CODE1.
CODE1A will preserve the property values beyond each run while CODE1B won't.
In case you're employing 'reference to list defined as property' technique for performance' sake, CODE1B should be better because it won't leave unwanted dirty data behind.

*Note that you should return the contents of the reference not the reference itself, if need be, especially when you're using this technique in one of your handler which is called many times.
E.g., if you return "my yy" in lieu of "my yy's contents" and use "set aa to main()" in lieu of "main()" in CODE1B, the dynamically instantiated script object (o) cannot be released even after the handler exits because there remains an object (aa) which is bound to it in the outer script. If you return "my yy's contents", the script object (o) can be released peacefully.



• Reduce the number of costly inter-application communications.

E.g. 2 Given -

--CODE2 (pseudo-code)
set xx to {}
repeat with i from 1 to 100
set end of xx to value of cell i
end
--END OF CODE2

--CODE2A (pseudo-code)
set xx to value of cells 1 thru 100
--END OF CODE2A

CODE2A (if it's possible) should be faster than CODE2.
(CODE2A sends 1 event while CODE2 sends 100 events to Numbers.)

E.g. 3 Given -

--CODE3 (pseudo-code)
repeat with i from 1 to 100
set value of cell i to (value of cell i) * -1
end repeat
--END OF CODE3

--CODE3A (pseudo-code)
property xx : {}
set xx to value of cells 1 thru 100
repeat with i from 1 to 100
set value of cell i to (my xx's item i) * -1
end repeat
--END OF CODE3A

CODE3A (if it's possible) should be faster than CODE3.
(CODE3A sends 101 events while CODE3 sends 200 events to Numbers.)



• If Numbers has its own script menu, call the script from there. In most cases, script run via application's own script menu runs (much) faster than script run as stand-alone applet. Perhaps AppleEvent addressing mode is different between them, I'd guess.

• Inter-application comunication in applet is slower than that in Script Editor. There's a way to improve applet's performance by using 'run script' command in applet.
Something like the following template, which is designed to preserve any properties in your main code (whether or not it is terminated by error).

*Note that this template swallows any error thrown in your main code. So it's not good for developing and/or debugging your code.

--APPLET TEMPLATE
script o
script o1
-- # place your main code here
end script
try
tell o1 to run
on error --
end try
return me
end script

set o to run script o -- to preserve the properties in o1
--END OF APPLET TEMPLATE

cf.
A relevant topic: Applet speed
http://discussions.apple.com/thread.jspa?threadID=1633798&tstart=0



Hope this may be of some help,
H

Message was edited by: Hiroto (fixed typo)

Jan 23, 2009 6:19 PM in response to Hiroto

Hiroto, thats a fantastic write up. Thanks for spending so much time typing all that out. I think I will be able to take that seudo code and make it work with Numbers. This is definitely going to help. I had no idea the "properties" would increase performance so much. I will probably stay up tonight and tomorrow and write some actual Numbers code and repost here under yours to convert (at least some) of the seudo code into Numbers code for other people that come across this posting later.

Once again,
Thanks very very much,
Jason

Jan 25, 2009 8:43 AM in response to Hiroto

Hi all of you

glad to meet Camelot, jason and Hiroto in the same thread.

We have a lot of things to discover in Numbers.

For Hiroto's information : Numbers has no specific script menu.

It obey the modern rule:

to reach the dedicated scripts from a menu, store them this way:
<startupVolume>:Users:<userAccount>:Library:Scripts:Applications:Numbers:transpo se4numbers.app:

Here you see ":" at the end of the path because I saves this kind of script as Application Bundle.

CAUTION, even Mac Os Hints may post a wrong script (I comment one of them in http://discussions.apple.com/thread.jspa?messageID=8770643)

For jason's information : Matt Neuburg's The Definitive Guide is a good source of infos.

For Camelot's information : If you know a way to tell GUIscripting which table of which sheet must be duplicated, I am interested 😉

Yvan KOENIG (from FRANCE dimanche 25 janvier 2009 17:43:42)

Making applescript run faster...

Welcome to Apple Support Community
A forum where Apple customers help each other with their products. Get started with your Apple ID.