2010-01-02 7 views
3

Je suis à la phase de débogage/optimisation avec une application iPhone. J'ai un goulot d'étranglement à gauche - le seul endroit où le programme a un retard notable, et il est dans la boucle suivante: (A propos, j'ai renommé les vars avec des lettres et des types. (Les vrais noms sont beaucoup plus lisibles par l'homme dans l'application réelle, mais peu de sens hors contexte, donc j'espère que cela est assez clair) est ici la boucle:..Cette boucle peut-elle être optimisée?

for(i=0;i<xLong; i+=yFloat*zShort){ 
    aFloat=0.0; 
    for(int j=i;j<i+yFloat*zShort;j++){ 
    aFloat=hArray[j]/kFloat; 
    } 
    bNSNumber = [NSNumber numberWithFloat:aFloat]; 
    [cNSMutableArray addObject:bNSNumber]; 
} 

Toute la création d'opposition et nettoyage est en dehors de cette boucle

(Il devrait être assez simple ce qui se passe ici, mais fondamentalement, j'ai un très grand tableau (dans les millions) et je passe par ce tableau à des morceaux de longueur yFloat * zShort, en ajoutant tous les éléments dans ce morceau, et insérer cette somme finale dans un autre tableau. si hArray est long d'un million d'éléments, et que ma longueur de segment est 200, je vais additionner les 200 premiers éléments, insérer ce total dans cNSMutableArray, et passer aux 200 éléments suivants dans hArray. À la fin, cNSMutableArray aura une longueur de 5000 éléments.)

Lorsque la boucle externe est d'environ 25k et la boucle interne d'environ 200, ce code prend environ 4 secondes pour s'exécuter. Je voudrais bien le faire le plus possible, car dans le monde réel, la boucle extérieure pourrait être un peu plus grande.

Des idées pour accélérer ce processus?

Merci pour vos idées!

Répondre

6

Tout d'abord, à partir de votre description, il semble que la boucle intérieure devrait lire:

for(int j=i;j<i+yFloat*zShort;j++){ 
    aFloat+=hArray[j]/kFloat; 
} 

Quoi qu'il en soit, étant donné que kFloat ne change pas, vous pouvez vous déplacer que de la boucle et de faire la division une fois:

for(int j=i;j<i+yFloat*zShort;j++){ 
    aFloat+=hArray[j]; 
} 
aFloat/=kFloat; 

Cela dit, cela peut affecter la précision de la valeur finale. Sans savoir exactement ce que vous faites, je ne sais pas si cela aura de l'importance.

+1

Ah ah! Vous avez trouvé un bug! Je ne résumais pas le bloc. Clairement c'était l'intention originale, mais il semble qu'à un certain moment, j'ai arrêté de faire cela, ce qui signifie que je venais de réinitialiser un Float à chaque pas, ce qui bien sûr je n'ai pas besoin de le faire. J'ai donc complètement supprimé la boucle interne, en définissant simplement la valeur à la première valeur de ce morceau et le temps est maintenant un quart de ce qu'il était. Merci! –

+0

@Eric Christensen: L'optimisation par la suppression des fonctionnalités est une approche intéressante. Je suis curieux de savoir pourquoi l'utilisation du premier élément est aussi bonne que la moyenne du bloc? –

+0

Le code que vous avez posté utilise réellement la dernière valeur du morceau, pas le premier si cela compte. –

8

Avez-vous essayé de créer un tableau flottant de style C au lieu d'utiliser NSMutableArray? la surcharge de créer autant de wrappers (NSNumber) peut s'additionner.

+0

Merci. A l'origine, la longueur des données n'était pas connue, mais maintenant c'est le cas, donc vous avez raison, il est logique de le convertir en un tableau de style C. Ça ira. –

0

Cela ressemble au type de calcul qui doit être effectué dans un thread d'arrière-plan.

Vous avez plusieurs NSOperation Options- est une alternative viable, mais en fonction de vos structures de données, il est peut-être plus facile à utiliser detachNewThreadSelector: toTarget: withObject:

+0

Malheureusement, il n'y a rien d'autre à faire pour l'utilisateur tant que la boucle n'est pas bouclée, donc ça n'a pas de sens pour moi de la faire tourner.Il n'y a pas de gain de vitesse pour les threads d'arrière-plan, n'est-ce pas? C'est juste que vous pouvez faire d'autres choses en même temps, n'est-ce pas? Merci. –

+0

Mais si l'objectif-c est quelque chose comme des formulaires Windows alors votre interface graphique se verrouillera, ce faisant cela vous permettra de faire une barre de progression ou quelque chose comme ça ... – RCIX

+0

Oui, c'est ce que je veux dire. Le verrouillage de l'interface graphique est très mauvais. Il est préférable d'afficher une barre de progression (annulable si possible) ou une indication que le travail est en cours. – sbooth

0

Vous voulez vraiment éviter de créer des objets dans une boucle serrée. Chaque fois que vous faites cela, vous allouer un nouvel objet sur le tas, ce qui implique un insert de hachage.

+0

Peut-être qu'il me manque quelque chose. Pour autant que je comprends, le code ci-dessus ne crée pas de nouveaux objets dans la boucle, non? –

2

Je vois que vous avez déjà obtenu une belle accélération, mais voici mes deux cents: Division à virgule flottante est notoirement chère; vous pouvez précalculer

float invKFloat = 1.0f/kFloat; 

puis par ce lieu Multiplier de diviser par kFloat. Cela signifie que vous devez seulement faire la division une fois, au lieu de chaque fois dans la boucle externe.

Questions connexes