Estoy dividido entre el diseño orientado a objetos y el diseño basado en vectores. Me encantan las habilidades, la estructura y la seguridad que los objetos dan a toda la arquitectura. Pero al mismo tiempo, la velocidad es muy importante para mí, y tener variables flotantes simples en una matriz realmente ayuda en lenguajes / bibliotecas basadas en vectores como Matlab o numpy en Python.
Aquí hay un fragmento de código que escribí para ilustrar mi punto
Problema: Agregar números de volatilidad de Tow. Si x e y son dos números de volatilidad, la suma de la volatilidad es (x ^ 2 + y ^ 2) ^ 0.5 (suponiendo cierta condición matemática pero eso no es importante aquí).
Quiero realizar esta operación muy rápido, y al mismo tiempo necesito asegurarme de que las personas no solo agreguen la volatilidad de la manera incorrecta (x + y). Ambos son importantes.
El diseño basado en OO sería algo como esto:
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))
(Aparte: para aquellos que son nuevos en Python, __add__
es solo una función que anula el +
operador)
Digamos que agrego listas de valores de volatilidad
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)))
(Aparte: una vez más, una serie en Python es una especie de lista con un índice) Ahora quiero agregar los dos:
t1 = datetime.now()
vs3 = vs1 + vs2
t2 = datetime.now()
print t2-t1
Solo la adición se ejecuta en 3.8 segundos en mi máquina, los resultados que he dado no incluyen el tiempo de inicialización del objeto, solo el código de adición que se ha cronometrado. Si ejecuto lo mismo usando matrices 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
Se ejecuta en 0.03 segundos. ¡Eso es más de 100 veces más rápido!
Como puede ver, la forma OOP me da mucha seguridad de que la gente no agregará Volatility de la manera incorrecta, ¡pero el método vectorial es tan rápido! ¿Hay un diseño en el que pueda obtener ambos? Estoy seguro de que muchos de ustedes se han encontrado con opciones de diseño similares, ¿cómo lo resolvieron?
La elección del idioma aquí es irrelevante. Sé que muchos de ustedes aconsejarían usar C ++ o Java, y el código puede ejecutarse más rápido que los lenguajes basados en vectores de todos modos. Pero ese no es el punto. Necesito usar Python, porque tengo una gran cantidad de bibliotecas que no están disponibles en otros idiomas. Esa es mi restricción. Necesito optimizar dentro de ella.
Y sé que mucha gente sugeriría paralelización, gpgpu, etc. Pero primero quiero maximizar el rendimiento de un solo núcleo, y luego puedo paralelizar ambas versiones de código.
¡Gracias por adelantado!
fuente
Respuestas:
Diseña objetos más grandes. Un
Pixel
objeto no tiene espacio para respirar para un bucle paralelo o transformaciones de imagen de GPU o algo así. SíImage
, siempre que no tenga que atravesar la barrera de unPixel
objeto pequeño para obtener los datos.fuente
Esta es una de esas áreas donde es imposible dar respuestas definitivas, ya que se trata de una compensación. Como descubrió, ni OO, ni basado en vectores siempre es superior, pero todo depende de cómo se utilizará el software.
Podría intentar combinar lo mejor de ambos y crear un
Volatility
objeto y unVolatilitySeries
objeto, donde el segundo representa conceptualmente una serie de objetos de volatilidad, pero internamente utiliza un método de almacenamiento que es mucho más adecuado para vectorizar los cálculos (una estructura de matrices) . Luego, solo tiene que educar a sus usuarios sobre el usoVolatilitySeries
preferibleSeries(Volatility)
.fuente
VolatilitySeries
como usted sugiere, entonces no puedo tener unlist
, o untuple
o (suponiendo que esté familiarizado con Python) aDataFrame
de elementos de volatilidad. Eso me molesta, porque entonces mi arquitectura no escala bien y los beneficios se desvanecen después de un tiempo. Y eso es lo que me trae aquí :).volatilitySeries[0] + 3.0
, lo que estará mal. Una vez que extrae los valoresVolatilitySeries
, puede volverse loco, por lo que la seguridad es de corta duración. En un entorno polimórfico donde las personas no siempre son conscientes de la clase exacta que se utiliza, esto es muy posible. Y ya sabes, solo puedes educar tanto a tus usuarios. Sé que dirás eso, oye, también puedo hacer lo mismo si me escabulloVolatility.value
, pero ya sabes, al menos el usuario sabe ahora que está usando un valor especial.Series
inVolatilitySeries
, pero eso frustra todo el propósito. Entonces, lo que aprendí al seguir ese camino es que tener unVolatilitySeries
objeto solo funciona a largo plazo si las celdas individuales son de tipoVolatility
.VolatileSeries
enfoque es viable. Si ya lo probaste y no funcionó, entonces tienes que elegir entre seguridad y velocidad. No podemos ayudarte allí. (a menos que alguien más tenga una respuesta brillante)