Petite étude: vitesse d'exécution de ibtool

tabliertablier Membre
12:49 modifié dans API AppKit #1
exécution-> pendu tout les matins sous les bras jusqu'à  ce que mort s'en suive!
Trêve de plaisanterie, J'ai des commandes du genre de celle ci-dessous à  exécuter:
Developer/usr/bin/ibtool  --export-strings-file /Users/msaro/AS/Main.strings  /Users/msaro/AA/Main.nib
J'ai commencé par utiliser AppleScript:
- (NSString *)doExecScript:(NSString *)commande<br />{<br />NSDictionary		*infoErreur ;<br /><br />	NSAppleScript *monScript = [[NSAppleScript alloc] initWithSource:commande] ; <br />	[monScript compileAndReturnError:&amp;infoErreur] ;<br />&nbsp; &nbsp; NSAppleEventDescriptor *descripteur = [monScript executeAndReturnError:&amp;infoErreur] ;<br />&nbsp; &nbsp; [monScript release];<br />&nbsp; &nbsp; if (descripteur == nil)<br />		return [NSString stringWithString:[infoErreur objectForKey:@&quot;NSAppleScriptErrorMessage&quot;]] ;<br />&nbsp; &nbsp;  else<br />		return @&quot;&quot;&nbsp; ;<br />}
ça marche, mais c'est lent!! je suis donc passé à  un appleEvent:
- (NSString *)doEventIbtool:(NSString *)commande<br />{<br />OSErr			err = noErr ;					<br />AppleEvent		toolEvent, reponse ;<br />char			commnd[512] ;<br /><br />	strcpy(commnd, [commande UTF8String]) ;<br />	err = AEBuildAppleEvent(&#39;syso&#39;,&#39;exec&#39;, typeProcessSerialNumber, &amp;locProcess, sizeof(locProcess),&nbsp;  <br />				kAutoGenerateReturnID, kAnyTransactionID, &amp;toolEvent, NULL, &quot;&#39;----&#39;:TEXT(@)&quot;,commnd )&nbsp; ;<br />	if (err == noErr)<br />	 {	err = AESendMessage (&amp;toolEvent, &amp;reponse, kAEWaitReply | kAECanInteract , kAEDefaultTimeout) ;<br />		(void) AEDisposeDesc(&amp;toolEvent);<br />		// ici, traitement de la réponse -------------<br />		(void) AEDisposeDesc(&amp;reponse);<br />	 } ;<br />	return @&quot;&quot;&nbsp; ;<br />}
ça marche et c'est plus rapide. Pour comparer, j'ai voulu utiliser NSTask:
- (NSString *)doShellTask<br />{<br />	NSArray *table = [NSArray arrayWithObjects:@&quot; --export-strings-file&quot;, @&quot;/Users/msaro/AS/Main.strings&quot;, <br />															@&quot;/Users/msaro/AA/Main.nib&quot;,&nbsp; nil ] ;<br />	NSTask&nbsp; *tache = [[NSTask alloc] init] ; <br />	[tache setLaunchPath:@&quot;Developer/usr/bin/ibtool &quot;] ;<br />	[tache setArguments:table] ;	<br />	NSPipe *pype = [NSPipe pipe] ;<br />	[tache setStandardOutput: pype] ;<br />	NSFileHandle *fich = [pype fileHandleForReading] ;<br /><br />	[tache launch];	<br />	[tache waitUntilExit];<br /><br />	NSData *data = [fich readDataToEndOfFile] ;<br />	NSString *string = [[NSString alloc] initWithData:data encoding: NSUTF8StringEncoding] ;<br />	[string release] ;<br />	[tache release] ;<br />	return @&quot;&quot;&nbsp; ;<br />}
Alors là , rien ne marche!! J'ai estimé qu'ibtool créait directement le fichier de sortie sans passer par la sortie standard. J'ai donc supprimé le pipe, le filehandle et le string final. Pas de différence, ça ne marche pas!
Donc, je dois faire une erreur monumentale et j'aimerais bien savoir laquelle!

Réponses

  • AliGatorAliGator Membre, Modérateur
    décembre 2010 modifié #2
    - Enlève l'espace devant "--export-strings-file" (le premier paramètre/objet de ton NSArray)
    - Enlève l'espace à  la fin du launchPath que tu mets à  ta task
    - Donne le bon chemin au launchPath de ta task (avec un "/" devant, sinon c'est pas un chemin absolu mais relatif au working directory qui doit être dans le contexte d'une NSTask un truc comme ton HomeFolder ou encore l'endroit du bundle de ton appli... bref normal qu'il ne trouve pas l'exécutable ibtool)

    Si ça ne marche toujours pas, rajoute un pipe (éventuellement le même) à  ta task pour setStandardError pour y récupérer la sorti de stderr (en plus de la sortie de stdout que tu récupères déjà  par setStandardOutput) car s'il y a une erreur à  l'exécution, c'est dans stderr que tu pourras la lire et comprendre ainsi pourquoi ça ne marche pas.


    PS : Reste une question : après cette réponse, si ça marche (et donc que c'était bien juste ces points la source de l'erreur), je me demande qui on doit exécuter finalement... :D :P
  • tabliertablier Membre
    12:49 modifié #3
    Tu as raison pour les espaces. Néanmoins, je viens de découvrir un truc curieux. Si j'écris
    &nbsp; NSArray *table = [NSArray arrayWithObjects:@&quot;--export-strings-file&quot;,<br />&nbsp; &nbsp; &nbsp; &nbsp; 	@&quot;/Users/msaro/Desktop/AS/Main.strings&quot;,<br />&nbsp; &nbsp; &nbsp; &nbsp; 	@&quot;/Users/msaro/Desktop/AA/French.model/Main.nib&quot; , nil] ;
    
    le compilateur ne me donne pas d'erreur, mais cette ligne met plus de 10 secondes à  être exécutée et la console affiche:
    Timed out fetching data. Variable display may be inaccurate. et bien sur le NSTask ne marche pas.
    Alors que si j'écris
    NSString *txts = [NSString stringWithString: @&quot;--export-strings-file§/Users/msaro/Desktop/AS/Main.strings§/Users/msaro/Desktop/AA/French.model/Main.nib&quot;] ;<br /> NSArray *table = [NSArray arrayWithArray:[txts componentsSeparatedByString:@&quot;§&quot;]] ;
    
    tout marche parfaitement et le NSTask fonctionne correctement!
    Quelque chose m'échappe!!
  • cyranocyrano Membre
    12:49 modifié #4
    et sans la sentinelle ?
  • tabliertablier Membre
    12:49 modifié #5
    Quelque soit le caractère de séparation, ça marche. j'ai essayé avec "§", "¶" et avec " ", pas de problème. Dans le modèle définitif, je fournirai directement le NSArray des arguments du NSTask, donc il ne devrait plus y avoir de caractère de séparation.
  • AliGatorAliGator Membre, Modérateur
    12:49 modifié #6
    Etrange

    Par contre rien à  voir avec ton problème mais c'est quoi cette manie d'utiliser stringWithString et arrayWithArray qui ne servent à  rien du tout et son des no-op (à  part si tu passes une NSMutableString pour la faire devenir NSString ou un NSMutableArray pour générer un NSArray mais là  c'est pas le cas alors bon :P)
  • cyranocyrano Membre
    12:49 modifié #7
    et sans la sentinelle ?
    


    je parlais de la sentinelle du tableau (nil)
  • AliGatorAliGator Membre, Modérateur
    12:49 modifié #8
    Sans la sentinelle tu auras un warning et un risque de crash (elle est pas là  pour rien la sentinelle et le NS_REQUIRES_NIL_TERMINATION) puisqu'elle sert à  arrêter le parsing de la liste. Ou alors faut utiliser "arrayWithObjects:count:"
  • tabliertablier Membre
    12:49 modifié #9
    Sans la sentinelle tu auras un warning et un risque de crash
    comme mes différentes commandes ont des nombres variables d'arguments, le nil est d'une grande facilité!
    Ben, dans mon exemple il y a des méthodes qui ne servent à  rien, oui, oui!!
    Je ne suis pas un expert  dans le maniement de la ram aussi je pense (peut être à  tord) qu'en ajoutant cela les variables "auto_released" ont leur compte qui augmente de 1.
    Dans le cas qui m'occupe, la version finale commence par:
    - (NSString *)doShellTask:(NSString *)commande
    {
    NSTask  *tache ;
    NSArray *table ;
    table = [commande componentsSeparatedByString:@â—Š] ;
    tache = [[NSTask alloc] init] ; // initialisation
    [tache setLaunchPath:ibnibtool] ; // chemin de l'appli ibtool
    [tache setArguments:table] ; // mettre les arguments
    ----  etc
    ce qui doit être correct je pense, même si on peut se passer de "table". Et j'ai garder l'habitude de déclarer les variables en tête des routines, pardon des méthodes. ça reste plus clair pour moi.
  • tabliertablier Membre
    12:49 modifié #10
    Voici mes résultats pour la comparaison entre les 3 manières de faire exécuter des commandes du type:
    Developer/usr/bin/ibtool  --export-strings-file /Users/msaro/AS/Main.strings  /Users/msaro/AA/Main.nib
    J'utilise le projet Cenon comme source des fichiers nib/xib, soit 50 fichiers nib/xib et 4 langues. Cela fait 200 exécutions de la commande.

    Objective C -> NSTask  51 secondes
    AppleScript -> do shell script ..  42 secondes
    Carbon -> AEBuildAppleEvent('syso','exec' ...  AESendMessage  38 secondes

    Il me semble que sous 10.6, AppleScript a été amélioré et fonctionne nettement plus vite qu'avant.
    Les AppleEvents sont plus rapides qu'AppleScript: c'est connu depuis longtemps.
    Les commandes sont construites par mon programme et sont directement utilisables par AppleScript et par Carbon. Pour NSTask, le programme extrait les arguments de la commande complète, ce qui fait une étape supplémentaire et ce qui explique peut-être les 51 secondes avec NSTask.
    Bien sur, ce type de comparaison n'est qu'indicative.

    Une possibilité que je n'ai pas regardé serait d'écrire les 200 commandes à  exécuter dans un fichier "shell-script" et de l'envoyer au shell pour exécution. Je ne sais pas si c'est possible, et le traitement des erreurs ne me parait pas évident.
Connectez-vous ou Inscrivez-vous pour répondre.