36 votes

Essayer / attraper ou valider pour la vitesse?

Je travaille avec Python et à chaque fois j'ai eu à valider l'entrée de la fonction, je suppose que l'entrée travaillé, et puis attrapé des erreurs.

Dans mon cas, j'ai eu un universel Vector() classe que j'ai utilisé pour plusieurs choses différentes, dont l'une est plus. Il fonctionne à la fois comme un Color() classe et en tant que Vector(), alors quand j'ai ajouter un scalaire à l' Color(), il faut ajouter que la constante de chaque composant individuel. Vector() et Vector() plus composant requis-sage plus.

Ce code est utilisé pour un raytracer de sorte que toute les boosts de vitesse sont grands.

Voici une version simplifiée de mon Vector() classe:

class Vector:
  def __init__(self, x, y, z):
    self.x = x
    self.y = y
    self.z = z

  def __add__(self, other):
    try:
      return Vector(self.x + other.x, self.y + other.y, self.z + other.z)
    except AttributeError:
      return Vector(self.x + other, self.y + other, self.z + other)

Je suis actuellement à l'aide de l' try...except méthode. Quelqu'un sait d'une méthode plus rapide?


EDIT: Merci pour les réponses, j'ai essayé et testé la solution suivante, qui vérifie en particulier pour un nom de classe avant d'ajouter l' Vector() objets:

class Vector:
  def __init__(self, x, y, z):
    self.x = x
    self.y = y
    self.z = z

  def __add__(self, other):
    if type(self) == type(other):
      return Vector(self.x + other.x, self.y + other.y, self.z + other.z)
    else:
      return Vector(self.x + other, self.y + other, self.z + other)

J'ai couru un test de vitesse avec ces deux blocs de code à l'aide d' timeit, et les résultats étaient assez importants:

 1.0528049469 usec/pass for Try...Except
 0.732456922531 usec/pass for If...Else
 Ratio (first / second): 1.43736090753

Je n'ai pas testé l' Vector() classe avec pas de validation de l'entrée que ce soit (c'est à dire le déplacement de la vérification de la classe et dans le code), mais j'imagine que c'est encore plus rapide que l' if...else méthode.


Fin de mise à jour: en Regardant en arrière à ce code, c'est pas une solution optimale.

OOP cela rend encore plus rapide:

class Vector:
  def __init__(self, x, y, z):
    self.x = x
    self.y = y
    self.z = z

  def __add__(self, other):
    return Vector(self.x + other.x, self.y + other.y, self.z + other.z)

class Color(Vector):
  def __add__(self, other):
    if type(self) == type(other):
      return Color(self.x + other.x, self.y + other.y, self.z + other.z)
    else:
      return Color(self.x + other, self.y + other, self.z + other)

80voto

ncoghlan Points 10779

Je upvoted Matt Menuisier réponse, mais je voulais y ajoutent quelques observations, il est clair que, avec un couple de d'autres facteurs, il y a 4 fois la question au moment de choisir entre la pré-vérification des conditions (connu sous le nom LBYL ou "Regarder Avant de Sauter") et de la gestion des exceptions (connu comme l'aeap ou "plus Facile de Demander Pardon que la Permission").

Ces horaires sont:

  • Quand le vérifier réussit avec LBYL
  • Calendrier lors de la vérification échoue avec LBYL
  • Quand une exception est pas jeté avec l'aeap
  • Quand une exception est levée avec l'aeap

Les autres facteurs sont les suivants:

  • Un rapport de vérification de la réussite/l'échec ou de l'exception levée/pas jeté cas
  • Si il y a ou non une condition de concurrence qui empêche l'utilisation de LBYL

Ce dernier point est celui qui doit être abordé en premier: si il y a un potentiel pour une condition de course, alors vous n'avez pas le choix, vous devez utiliser la gestion des exceptions. Un exemple classique est:

if <dir does not exist>:
    <create dir> # May still fail if another process creates the target dir

Depuis LBYL n'exclut pas l'exception dans ces cas là, il n'offre aucun avantage réel et il n'y a pas de jugement d'appel doit être faite: l'aeap est la seule approche qui va gérer la condition de la course correctement.

Mais si il n'y a pas de condition de course, que ce soit l'approche est potentiellement viable. Ils offrent différents arbitrages:

  • si aucune exception n'est levée, puis l'aeap est proche de libre
  • cependant, il est relativement cher si une exception se produit, comme il y a beaucoup de traitement impliqués dans le déroulement de la pile, de la création de l'exception et de la comparer à l'exception de la manipulation des clauses
  • LBYL, en revanche, n'encourt potentiellement un coût fixe élevé: le contrôle supplémentaire est toujours effectué, indépendamment du succès ou de l'échec

Cela nous amène à la suite de la décision de critères:

  • Est ce morceau de code connu pour être critique à la vitesse de l'application? Si non, alors ne vous inquiétez pas lequel des deux est le plus rapide, ne vous inquiétez de savoir lequel des deux est plus facile à lire.
  • Est le pre-check plus cher que le coût de la collecte et de l'interception d'une exception? Si oui, alors l'aeap est toujours plus rapide et devrait être utilisé.
  • Les choses sont encore plus intéressantes si la réponse est "non". Dans ce cas, qui est plus rapide dépendra de la réussite ou de l'erreur de cas est le plus fréquent, et les vitesses relatives de la pré-contrôle et la gestion des exceptions. Répondre à ce définitivement nécessite réel les mesures de temps.

Comme une règle simple:

  • si il y a un potentiel condition de course, utilisez l'aeap
  • si la vitesse n'est pas grave, il suffit d'utiliser celui que vous considérez plus facile à lire
  • si le pré-enregistrement est cher, utiliser l'aeap
  • si vous vous attendez le succès de l'opération, la plupart du temps*, utiliser l'aeap
  • si vous vous attendez à l'échec de l'opération de plus de la moitié du temps, l'utilisation LBYL
  • si le doute persiste, il

*Les personnes variera en fonction de ce qu'il considère comme "la plupart du temps" dans ce contexte. Pour moi, si j'attends le succès de l'opération, plus de la moitié du temps, je voudrais juste utiliser l'aeap comme une question de cours, jusqu'à ce que j'ai eu raison de soupçonner ce morceau de code a été une véritable goulot d'étranglement des performances.

5voto

Matt Joiner Points 29194

En Python, les exceptions sont souvent plus rapides en raison du nombre réduit de recherches. Cependant, un ami a dit un jour (et cela devrait s’appliquer à n’importe quelle langue), prétendez que chaque fois qu’une exception est détectée, il ya un petit délai. Évitez d’utiliser des exceptions où un retard pourrait être un problème.

Dans l'exemple que vous avez donné, j'irais avec l'exception.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X