Programmazione orientata agli oggetti vs vettoriale


14

Sono diviso tra design orientato agli oggetti e design basato sul vettore. Adoro le capacità, la struttura e la sicurezza che gli oggetti danno all'intera architettura. Ma allo stesso tempo, la velocità è molto importante per me e avere semplici variabili float in un array aiuta davvero in linguaggi / librerie basati su vettori come Matlab o numpy in Python.

Ecco un pezzo di codice che ho scritto per illustrare il mio punto

Problema: aggiunta di numeri di volatilità di rimorchio. Se xey sono due numeri di volatilità, la somma della volatilità è (x ^ 2 + y ^ 2) ^ 0,5 (presupponendo determinate condizioni matematiche ma non è importante qui).

Voglio eseguire questa operazione molto velocemente e allo stesso tempo devo assicurarmi che le persone non aggiungano semplicemente la volatilità nel modo sbagliato (x + y). Entrambi sono importanti.

Il design basato su OO sarebbe qualcosa del genere:

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))

(A parte: per coloro che sono nuovi a Python, __add__è solo una funzione che sovrascrive l' +operatore)

Diciamo che aggiungo liste di rimorchio di valori di 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))) 

(A parte: ancora una serie in Python è una specie di elenco con un indice) Ora voglio aggiungere i due:

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

Solo l'aggiunta viene eseguita in 3,8 secondi sulla mia macchina, i risultati che ho fornito non includono affatto il tempo di inizializzazione dell'oggetto, è solo il codice di aggiunta che è stato cronometrato. Se eseguo la stessa cosa usando array intorpiditi:

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

Funziona in 0,03 secondi. È più di 100 volte più veloce!

Come puoi vedere, il modo OOP mi dà molta sicurezza che le persone non aggiungeranno volatilità nel modo sbagliato, ma il metodo vettoriale è così follemente veloce! Esiste un design in cui posso ottenere entrambi? Sono sicuro che molti di voi si sono imbattuti in scelte progettuali simili, come ci sono riuscito?

La scelta della lingua qui è irrilevante. So che molti di voi consiglierebbero l'uso di C ++ o Java, e il codice potrebbe comunque funzionare più velocemente dei linguaggi basati su vettori. Ma non è questo il punto. Devo usare Python, perché ho una serie di librerie non disponibili in altre lingue. Questo è il mio vincolo. Ho bisogno di ottimizzare al suo interno.

E so che molte persone suggerirebbero parallelizzazione, gpgpu ecc. Ma prima voglio massimizzare le prestazioni single core, quindi posso parallelizzare entrambe le versioni del codice.

Grazie in anticipo!


3
Un modo strettamente correlato per pensare a questo problema: dovresti usare una struttura di array (SoA) o un array di strutture (AoS) per le prestazioni? Con SoA più facile da vettorializzare e AoS più OOP-friendly nella maggior parte delle lingue.
Patrick,

si @Patrick, se vedi la prima risposta, penso che Bart abbia dato un esempio pratico del punto che stai sollevando. Ho ragione? Ho notato che dici la maggior parte delle lingue, quindi ci sono lingue in cui entrambe sono vicine nelle prestazioni?
Ramanuj Lal,

Risposte:


9

Come puoi vedere, il modo OOP mi dà molta sicurezza che le persone non aggiungeranno volatilità nel modo sbagliato, ma il metodo vettoriale è così follemente veloce! Esiste un design in cui posso ottenere entrambi? Sono sicuro che molti di voi si sono imbattuti in scelte progettuali simili, come ci sono riuscito?

Progetta oggetti più grandi. Un Pixeloggetto non ha spazio per un ciclo parallelo o trasformazioni di immagini GPU o cose del genere. A Imagecondizione che non sia necessario attraversare la barriera di un Pixeloggetto teeny per ottenere i dati.


5

Questa è una di quelle aree in cui è impossibile dare risposte definitive, perché riguarda un compromesso. Come hai scoperto, né OO, né basato su vettori sono sempre superiori, ma tutto dipende da come verrà utilizzato il software.

Potresti provare a combinare il meglio di entrambi e creare sia un Volatilityoggetto che un VolatilitySeriesoggetto, in cui il secondo rappresenta concettualmente una serie di oggetti di volatilità, ma utilizza internamente un metodo di archiviazione che è molto più adatto per vettorializzare i calcoli (una struttura di array) . Quindi devi solo educare i tuoi utenti che l'utilizzo VolatilitySeriesè molto preferibile Series(Volatility).


Grazie Bart, è una buona idea. In effetti sono andato così nel mio attuale progetto in alcune parti, dove alcuni oggetti come importi monetari sono stati riprogettati in quel modo. Ma presto ho capito che il mio codice diventa uno schiavo di quella particolare struttura di dati. Ad esempio, se ho una VolatilitySeriescome suggerisci, non posso avere una list, o una tupleo (supponendo che tu abbia familiarità con Python) una DataFramedelle voci di volatilità. Questo mi preoccupa, perché la mia architettura non si adatta bene e i benefici svaniscono dopo un po '. E questo è ciò che mi porta qui :).
Ramanuj Lal,

L'altro problema è che nulla impedisce a nessuno di scrivere un codice simile volatilitySeries[0] + 3.0, il che sarà sbagliato. Una volta sottratti valori VolatilitySeries, puoi impazzire, quindi la sicurezza è solo di breve durata. In un ambiente polimorfico in cui le persone non sono sempre consapevoli dell'esatta classe utilizzata, questo è altamente possibile. E sai, puoi solo educare così tanto i tuoi utenti. So che lo dirai, ehi, posso anche fare la stessa cosa se sbaglio Volatility.value, ma sai, almeno l'utente è consapevole ora che sta usando un valore speciale.
Ramanuj Lal,

Alcuni potrebbero anche suggerire che sovrascrivono tutte quelle solite funzioni ereditate da Seriesin VolatilitySeries, ma che vanifica l'intero scopo. Quindi quello che ho imparato seguendo questo percorso è che avere un VolatilitySeriesoggetto funziona davvero a lungo termine solo se le singole celle sono di tipo Volatility.
Ramanuj Lal,

@RamanujLal: non conosco abbastanza bene Python per determinare se l' VolatileSeriesapproccio è praticabile. Se l'hai già provato e non ha funzionato, allora hai una difficile scelta tra sicurezza e velocità. Non possiamo aiutarti lì. (a meno che qualcun altro abbia una risposta brillante)
Bart van Ingen Schenau,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.