L'exécution des scripts AppleScript avec Numbers n'est pas franchement un modèle de vitesse. Pour être franc, on a tout le temps d'admirer et de comprendre ce qui se passe.
Prenons un exemple.
Lançons Numbers et créons un nouveau document. Retaillons la tableau de façon à ce qu'il fasse dix colonnes et trente lignes.
Ouvrons l'Éditeur AppleScript et lançons ça :
- Code:
-
-- version 1
tell application "Numbers"
set debut to (current date)
activate
tell document 1
repeat with s from 1 to the count of sheets
tell sheet s
repeat with t from 1 to the count of tables
clear every cell of table t
tell table t
repeat with c from 1 to the count of cells
if c = 1 then
set the value of cell c to "=alea()"
else
set the value of cell c to ¬
"=" & the name of cell (c - 1) & "/10+alea()"
end if
end repeat
repeat with c from 1 to the count of cells
set the value of cell c to 1
end repeat
end tell
end repeat
end tell
end repeat
end tell
set fin to (current date)
activate
display dialog (fin - debut)
end tell
Sur ma machine, ça prend 59 secondes.
En fait, à chaque modification de cellule, Numbers recalcule les tableaux visibles.
Donc, plus il y a de cellules qui dépendent de celle qu'on modifie, plus le temps de recalcul est long.
C'est ce qui se passe quand on fait la deuxième boucle (et, dans une moindre mesure, lors de la première).
Je me suis dit qu'on gagnerait peut-être en temps d'exécution si on pouvait mettre au premier plan une feuille sur laquelle n'aurait lieu aucune opération. Voici le code :
- Code:
-
-- version 2
tell application "Numbers"
set debut to (current date)
activate
tell document 1
set masksheet to make new sheet
set the value of cell 1 of table 1 of masksheet to "Patientez..."
repeat with s from 1 to the count of sheets
if sheet s is not masksheet then
tell sheet s
repeat with t from 1 to the count of tables
clear every cell of table t
tell table t
repeat with c from 1 to the count of cells
if c = 1 then
set the value of cell c to "=alea()"
else
set the value of cell c to ¬
"=" & the name of cell (c - 1) & "/10+alea()"
end if
end repeat
repeat with c from 1 to the count of cells
set the value of cell c to 1
end repeat
end tell
end repeat
end tell
end if
end repeat
try
delete masksheet
end try
end tell
set fin to (current date)
activate
display dialog (fin - debut)
end tell
Bingo ! Il ne faut plus que 8 secondes.
Bon, le code est un peut plus compliqué puisqu'il faut soigneusement éviter de toucher à la feuille de masquage dont la présence n'est que temporaire.
Au demeurant, ceux qui ont déjà programmé Excel en VBA savent qu'il existe des moyens d'empêcher le recalcul le temps du traitement et qu'on peut éviter la mise à jour de l'interface pour booster l'exécution du code.
On est un peu dans une problématique du même genre.
Bref.
Je me suis ensuite demandé si on gagnerait encore du temps en cachant Numbers le temps du traitement :
- Code:
-
-- version 3
tell application "Numbers"
set debut to (current date)
activate
-- la ligne suivante est optionnelle et n'apporte pas grand chose
tell application "System Events" to keystroke "h" using {command down}
tell document 1
set masksheet to make new sheet
set the value of cell 1 of table 1 of masksheet to "Patientez..."
repeat with s from 1 to the count of sheets
if sheet s is not masksheet then
tell sheet s
repeat with t from 1 to the count of tables
clear every cell of table t
tell table t
repeat with c from 1 to the count of cells
if c = 1 then
set the value of cell c to "=alea()"
else
set the value of cell c to ¬
"=" & the name of cell (c - 1) & "/10+alea()"
end if
end repeat
repeat with c from 1 to the count of cells
set the value of cell c to 1
end repeat
end tell
end repeat
end tell
end if
end repeat
try
delete masksheet
end try
end tell
set fin to (current date)
activate
display dialog (fin - debut)
end tell
Ce n'est pas ultra formidable mais on gagne encore 2 secondes.
Sur un traitement plus important, ça peut faire la différence.
Maintenant, recommençons les mêmes opérations en enregistrant au préalable le script dans le dossier des scripts Numbers et lançons-le depuis le tableur.
On obtient les temps suivants :
- version 1 : 66 secondes
- version 2 : 19 secondes
- version 3 : 18 secondes
Bigre ! Il est donc plus long d'exécuter un script depuis l'appli que depuis l'éditeur. Why ? I just don't know.
J'avais
déjà remarqué ça.
Mais devoir ouvrir le script dans l'éditeur juste pour l'accélérer, c'est contraignant.
J'ai essayé de le lancer depuis le Terminal pour voir :
- Code:
-
osascript ~/Library/Scripts/Applications/Numbers/test.scpt
Super ! On revient aux temps constatés dans l'éditeur.
J'ai donc créé un second script d'emballage :
- Code:
-
do shell script "osascript ~/Library/Scripts/Applications/Numbers/test.scpt"
En l'appelant depuis Numbers, comme il sous-traite le boulot au processeur de scripts, on ne constate plus de baisse de régime. Cool !
Mais devoir gérer deux scripts, quelle plaie.
Heureusement, les ressources de l'imagination sont sans limite...
On peut demander au script de se sous-traiter lui-même à osascript.
Il faut quand même éviter que ça ne boucle ; il va donc s'appeler avec un paramètre disant qu'il s'est appelé pour éviter qu'il ne s'appelle à nouveau.
Donc, quand on l'appelle, il s'appelle sans faire le boulot de façon à faire le boulot sans s'appeler. C'est clair ?
Bref, voilà le code :
- Code:
-
-- version 4
on run argv
if the (count of argv) is 0 then
do shell script "osascript " & POSIX path of (path to me) & " YES!"
else
tell application "Numbers"
set debut to (current date)
activate
-- la ligne suivante est optionnelle et n'apporte pas grand chose
-- tell application "System Events" to keystroke "h" using {command down}
tell document 1
set masksheet to make new sheet
set the value of cell 1 of table 1 of masksheet to "Patientez..."
repeat with s from 1 to the count of sheets
if sheet s is not masksheet then
tell sheet s
repeat with t from 1 to the count of tables
clear every cell of table t
tell table t
repeat with c from 1 to the count of cells
if c = 1 then
set the value of cell c to "=alea()"
else
set the value of cell c to ¬
"=" & the name of cell (c - 1) & "/10+alea()"
end if
end repeat
repeat with c from 1 to the count of cells
set the value of cell c to 1
end repeat
end tell
end repeat
end tell
end if
end repeat
try
delete masksheet
end try
end tell
set fin to (current date)
activate
display dialog (fin - debut)
end tell
end if
end run
7 secondes chrono.
On peut réemployer cette astuce de façon générique :
- Code:
-
on run argv
if the (count of argv) is 0 then
do shell script "osascript " & POSIX path of (path to me) & " YES!"
else
-- INSERER VOTRE CODE ICI
end if
end run
Attention : il faut que le code inséré soit déverminé sérieusement car les erreurs peuvent être masquées par ce procédé.
>> Basé sur Numbers '09 (2.0.3) et AppleScript 2.1.2