Programmation orientée objet vs vectorielle

14

Je suis partagé entre la conception orientée objet et la conception vectorielle. J'adore les capacités, la structure et la sécurité que les objets donnent à toute l'architecture. Mais en même temps, la vitesse est très importante pour moi, et avoir de simples variables flottantes dans un tableau aide vraiment dans les langages / bibliothèques vectoriels comme Matlab ou numpy en Python.

Voici un morceau de code que j'ai écrit pour illustrer mon propos

Problème: ajout de numéros de volatilité Tow. Si x et y sont deux nombres de volatilité, la somme de la volatilité est (x ^ 2 + y ^ 2) ^ 0,5 (en supposant une certaine condition mathématique mais ce n'est pas important ici).

Je veux effectuer cette opération très rapidement, et en même temps, je dois m'assurer que les gens n'ajoutent pas seulement la volatilité de la mauvaise façon (x + y). Ces deux éléments sont importants.

La conception basée sur OO ressemblerait à ceci:

from datetime import datetime 
from pandas import *

class Volatility:
    def __init__(self,value):
       self.value = value

    def __str__(self):
       return "Volatility: "+ str(self.value)

    def __add__(self,other):
        return Volatility(pow(self.value*self.value + other.value*other.value, 0.5))

(En plus: pour ceux qui sont nouveaux dans Python, __add__c'est juste une fonction qui remplace l' +opérateur)

Disons que j'ajoute des listes de remorquage des valeurs de volatilité

n = 1000000
vs1 = Series(map(lambda x: Volatility(2*x-1.0), range(0,n)))
vs2 = Series(map(lambda x: Volatility(2*x+1.0), range(0,n))) 

(À côté: Encore une fois, une série en Python est une sorte de liste avec un index) Maintenant, je veux ajouter les deux:

t1 = datetime.now()
vs3 = vs1 + vs2
t2 = datetime.now()
print t2-t1

L'addition s'exécute en 3,8 secondes sur ma machine, les résultats que j'ai donnés n'incluent pas du tout le temps d'initialisation de l'objet, c'est le seul code d'addition qui a été chronométré. Si je lance la même chose en utilisant des tableaux numpy:

nv1 = Series(map(lambda x: 2.0*x-1.0, range(0,n)))
nv2 = Series(map(lambda x: 2.0*x+1.0, range(0,n)))

t3 = datetime.now()
nv3 = numpy.sqrt((nv1*nv1+nv2*nv2))
t4 = datetime.now()
print t4-t3

Il s'exécute en 0,03 secondes. C'est plus de 100 fois plus rapide!

Comme vous pouvez le voir, la méthode OOP me donne beaucoup de sécurité pour que les gens n'ajoutent pas la volatilité de la mauvaise façon, mais la méthode vectorielle est tellement rapide et folle! Existe-t-il un design dans lequel je peux obtenir les deux? Je suis sûr que beaucoup d'entre vous ont rencontré des choix de conception similaires, comment avez-vous procédé?

Le choix de la langue ici est sans importance. Je sais que beaucoup d'entre vous conseillent d'utiliser C ++ ou Java, et le code peut s'exécuter plus rapidement que les langages vectoriels. Mais ce n'est pas le but. J'ai besoin d'utiliser Python, car j'ai une multitude de bibliothèques non disponibles dans d'autres langues. Voilà ma contrainte. J'ai besoin d'optimiser en son sein.

Et je sais que beaucoup de gens suggéreraient la parallélisation, gpgpu, etc. Mais je veux d'abord maximiser les performances du noyau unique, puis je peux paralléliser les deux versions de code.

Merci d'avance!

Ramanuj Lal
la source
3
Une manière étroitement liée de penser à ce problème: devez-vous utiliser une structure de tableaux (SoA) ou un tableau de structures (AoS) pour les performances? SoA étant plus facile à vectoriser et AoS étant plus convivial pour la POO dans la plupart des langues.
Patrick
oui @Patrick, si vous voyez la première réponse, je pense que Bart a donné un exemple pratique de votre argument. Ai-je raison? Je remarque que vous dites la plupart des langues, alors y a-t-il des langues où les deux sont proches en termes de performances?
Ramanuj Lal

Réponses:

9

Comme vous pouvez le voir, la méthode OOP me donne beaucoup de sécurité pour que les gens n'ajoutent pas la volatilité de la mauvaise façon, mais la méthode vectorielle est tellement rapide et folle! Existe-t-il un design dans lequel je peux obtenir les deux? Je suis sûr que beaucoup d'entre vous ont rencontré des choix de conception similaires, comment avez-vous procédé?

Concevez des objets plus gros. Un Pixelobjet n'a pas de marge de manœuvre pour une boucle parallélisée ou des transformations d'image GPU ou quelque chose comme ça. Une Imagebête à condition de ne pas avoir à passer la barrière d'un petit Pixelobjet pour accéder aux données.


la source
5

C'est l'un de ces domaines où il est impossible de donner des réponses définitives, car il s'agit d'un compromis. Comme vous l'avez découvert, ni OO, ni basé sur des vecteurs n'est toujours supérieur, mais tout dépend de la façon dont le logiciel sera utilisé.

Vous pouvez essayer de combiner le meilleur des deux et créer à la fois un Volatilityobjet et un VolatilitySeriesobjet, où le second représente conceptuellement une série d'objets de volatilité, mais utilise en interne une méthode de stockage bien mieux adaptée à la vectorisation des calculs (une structure de tableaux) . Ensuite, il vous suffit d'éduquer vos utilisateurs sur le fait qu'il VolatilitySeriesest préférable d' utiliser Series(Volatility).

Bart van Ingen Schenau
la source
Merci Bart, c'est une bonne idée. En fait, je suis allé de cette façon dans ma conception actuelle en plusieurs parties, où certains objets comme les montants monétaires ont été repensés de cette façon. Mais je me suis vite rendu compte que mon code devenait l'esclave de cette structure de données particulière. Par exemple, si j'ai un VolatilitySeriescomme vous le suggérez, je ne peux pas avoir un list, ou un tupleou (en supposant que vous connaissez Python) un DataFramedes éléments de volatilité. Cela me dérange, car alors mon architecture ne s'adapte pas bien et les avantages disparaissent après un certain temps. Et c'est ce qui m'amène ici :).
Ramanuj Lal
L'autre problème est que rien n'empêche quiconque d'écrire un code comme volatilitySeries[0] + 3.0, ce qui sera faux. Une fois que vous avez supprimé les valeurs VolatilitySeries, vous pouvez devenir fou, donc la sécurité n'est que de courte durée. Dans un environnement polymorphe où les gens ne sont pas toujours conscients de la classe exacte utilisée, cela est hautement possible. Et vous savez, vous ne pouvez éduquer que vos utilisateurs. Je sais que vous direz cela, hé je peux aussi faire la même chose si je me tortille Volatility.value, mais vous savez, au moins l'utilisateur est conscient maintenant qu'il utilise une valeur spéciale.
Ramanuj Lal
Certains peuvent également suggérer de remplacer toutes ces fonctions habituelles héritées de Seriesin VolatilitySeries, mais cela va à l'encontre de l'objectif global. Donc, ce que j'ai appris en descendant ce chemin, c'est qu'avoir un VolatilitySeriesobjet ne fonctionne vraiment à long terme que si les cellules individuelles sont de type Volatility.
Ramanuj Lal
@RamanujLal: Je ne connais pas assez bien le python pour déterminer si l' VolatileSeriesapproche est viable. Si vous l'avez déjà essayé et que cela n'a pas fonctionné, vous avez un choix difficile à faire entre sécurité et vitesse. Nous ne pouvons pas vous y aider. (sauf si quelqu'un d'autre a une réponse brillante)
Bart van Ingen Schenau