Measure first
Most code is fast enough, and the slow part of a program is rarely where you would guess. So before changing anything for speed, measure: the milliseconds before and after (Timers and waiting), on data as big as the real thing. The examples here time two ways of doing the same work and check that the faster really is faster; each says how the two compared on the computer that checked this page.
function timeIt pHandler
local tStart
put the milliseconds into tStart
dispatch pHandler to me
return the milliseconds - tStart
end timeIt
on countToAMillion
repeat with i = 1 to 1000000
end repeat
end countToAMillion
put "a million empty loops:" && timeIt("countToAMillion") && "ms"
a million empty loops: 1139 ms
Going through lines: repeat for each
This is the biggest one. line i of tText has to count returns from the start of the text every time, so a loop over all the lines with it counts the first lines again and again: twice the lines takes four times as long. repeat for each line walks through the text once:
repeat with i = 1 to 10000
put "line number" && i & return after tText
end repeat
put the milliseconds into tStart
repeat with i = 1 to the number of lines of tText
get line i of tText
end repeat
put the milliseconds - tStart into tByNumber
put the milliseconds into tStart
repeat for each line tLine in tText
get tLine
end repeat
put the milliseconds - tStart into tForEach
put "for each is at least 5 times faster:" && (tByNumber > 5 * max(1, tForEach))
for each is at least 5 times faster: true
With 20,000 lines, the check took about 1700 milliseconds by number and 35 with for each. The same goes for item i, word i and char i. When you need the number too, count it yourself inside a for each loop. And put the text into an array with split when you must jump to any line by its number many times (Algorithms).
Looking things up: arrays
is among the lines of, lineOffset and contains search from the start each time. To ask "have I seen this?" many times, keep the things as the keys of an array: finding a key takes the same short time however big the array is.
repeat with i = 1 to 5000
put "user" & i & return after tList
put true into tSet["user" & i]
end repeat
put the milliseconds into tStart
repeat with i = 1 to 5000
get ("user" & i) is among the lines of tList
end repeat
put the milliseconds - tStart into tSearch
put the milliseconds into tStart
repeat with i = 1 to 5000
get tSet["user" & i] is true
end repeat
put the milliseconds - tStart into tKeys
put "the array is at least 3 times faster:" && (tSearch > 3 * max(1, tKeys))
the array is at least 3 times faster: true
Let the engine do the loop
filter, sort, replace, split, combine, offset and the array commands (Array tools) loop inside the engine, in compiled code, much faster than a repeat written in xTalk can:
repeat with i = 1 to 50000
put i & return after tNumbers
end repeat
put the milliseconds into tStart
repeat for each line tN in tNumbers
if tN ends with "7" then put tN & return after tByHand
end repeat
put the milliseconds - tStart into tLoop
put the milliseconds into tStart
put tNumbers into tFiltered
filter tFiltered with "*7"
put the milliseconds - tStart into tFilter
put the number of lines of tByHand && the number of lines of tFiltered
put "filter is at least 5 times faster:" && (tLoop > 5 * max(1, tFilter))
5000 5000 filter is at least 5 times faster: true
Work in variables, not in fields
A field is an object on the screen: every change to its text is laid out, and drawn when the screen next updates. Build the text in a variable, and put it into the field once:
create field "Log"
put the milliseconds into tStart
repeat 2000 times
put "x" after field "Log"
end repeat
put the milliseconds - tStart into tField
put empty into field "Log"
put the milliseconds into tStart
repeat 2000 times
put "x" after tText
end repeat
put tText into field "Log"
put the milliseconds - tStart into tVariable
put "the variable is at least 10 times faster:" && (tField > 10 * max(1, tVariable))
the variable is at least 10 times faster: true
The same holds for any property read in a loop: the number of lines of field "Log" or the text of a field asked for on every pass. Read it once into a variable before the loop.
Changing many controls: lock screen
When a handler moves, hides or recolours many controls, the screen may be redrawn after each change. lock screen holds the drawing until the handler ends or unlock screen, so the user sees one finished change, sooner (Animation and games uses it for every frame). lock messages similarly stops openCard, setProp and other messages while a script goes through many cards or objects, for a script that only needs to look at them.
on recolourEverything pColour
lock screen
repeat with i = 1 to the number of controls of this card
set the backgroundColor of control i of this card to pColour
end repeat
unlock screen
end recolourEverything
on countAllFields
local tCount
lock messages
repeat with i = 1 to the number of cards of this stack
add the number of fields of card i of this stack to tCount
end repeat
unlock messages
return tCount
end countAllFields
Try it yourself
This function finds the words that appear more than once in a text, but it looks each word up in a list of the words so far, and gets slow as the text grows. Rewrite it with an array of counts, check that both give the same answer for the cat saw the dog and the dog saw the cat, and put the repeated words, sorted.
function repeatedWords pText
local tSeen, tRepeated
repeat for each word tWord in pText
if tWord is among the lines of tSeen and tWord is not among the lines of tRepeated then
put tWord & return after tRepeated
end if
put tWord & return after tSeen
end repeat
sort tRepeated
return line 1 to -1 of tRepeated
end repeatedWords
put repeatedWords("the cat saw the dog and the dog saw the cat")
cat dog saw the
Show a solution
function repeatedWords pText
local tCount, tWord, tRepeated
repeat for each word tWord in pText
add 1 to tCount[tWord]
end repeat
repeat for each key tWord in tCount
if tCount[tWord] > 1 then put tWord & return after tRepeated
end repeat
sort tRepeated
return line 1 to -1 of tRepeated
end repeatedWords
put repeatedWords("the cat saw the dog and the dog saw the cat")
cat dog saw the
Each word is now looked up as a key, in the same short time however many words came before, so twice the text takes about twice as long, not four times.
Words in this lesson
Each one finds every lesson that uses it. The Dictionary has the whole story of each, with its syntax and more examples.