面向对象与基于矢量的编程


14

我陷入了面向对象和基于矢量的设计之间。我喜欢对象赋予整个建筑的能力,结构和安全性。但是同时,速度对我来说非常重要,并且在数组中具有简单的float变量确实对基于矢量的语言/库(例如Matlab或Python中的numpy)有所帮助。

这是我写来说明我的观点的一段代码

问题:添加拖车波动率数字。如果x和y是两个波动率数字,则波动率的总和为(x ^ 2 + y ^ 2)^ 0.5(假设有一定的数学条件,但在这里并不重要)。

我想非常快地执行此操作,同时我需要确保人们不要以错误的方式(x + y)添加波动率。两者都很重要。

基于面向对象的设计将是这样的:

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

(此外:对于那些不熟悉Python的人来说,__add__它只是一个覆盖+运算符的函数)

假设我添加了两个波动率列表

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

(此外:同样,Python中的系列是带有索引的列表)现在我想添加两个:

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

只是加法在我的机器上运行了3.8秒,我给出的结果根本不包括对象初始化时间,仅是定时的加法代码。如果我使用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

运行时间为0.03秒。快100倍!

如您所见,OOP方法为我提供了很多安全性,人们不会以错误的方式添加Volatility,但是vector方法是如此之快!有没有我可以兼得的设计?我敢肯定,你们中很多人都遇到过类似的设计选择,您是如何实现的呢?

这里的语言选择无关紧要。我知道很多人建议使用C ++或Java,并且无论如何,这些代码的运行速度可能比基于矢量的语言要快。但这不是重点。我需要使用Python,因为我有许多其他语言都没有的库。那是我的约束。我需要在其中进行优化。

而且我知道,很多人会建议并行化,gpgpu等。但是我想先最大化单核性能,然后才能并行化两个代码版本。

提前致谢!


3
考虑此问题的一种密切相关的方法:应该使用数组结构(SoA)还是结构数组(AoS)来提高性能?在大多数语言中,SoA易于矢量化,而AoS则对OOP更友好。
帕特里克

是的@Patrick,如果您看到第一个答案,我认为Bart给出了您要表达的观点的实际例子。我对吗?我注意到您说的是大多数语言,那么是否有两种语言的性能接近?
Ramanuj Lal 2013年

算法+数据结构=程序通过尼克劳斯·维尔特
radarbob

Answers:


9

如您所见,OOP方法为我提供了很多安全性,人们不会以错误的方式添加Volatility,但是vector方法是如此之快!有没有我可以兼得的设计?我敢肯定,你们中很多人都遇到过类似的设计选择,您是如何实现的呢?

设计更大的对象。一个Pixel对象没有并行空间或GPU图像转换之类的呼吸空间。一个Image没有提供它并没有去通过一个很小的屏障Pixel对象获取的数据。


5

这是不可能给出确切答案的领域之一,因为它涉及到权衡。正如您发现的那样,OO和基于向量的方法都不总是优越的,但是这完全取决于软件的使用方式。

您可以尝试将两者的优点结合起来,创建一个Volatility对象和一个VolatilitySeries对象,其中第二个概念上表示一系列波动性对象,但内部使用的存储方法更适合对计算进行矢量化处理(数组结构) 。然后,您只需要教育您的用户,使用VolatilitySeries优于Series(Volatility)


谢谢Bart,这是个好主意。实际上,我在当前的零件设计中已经采用了这种方式,其中一些对象(例如货币金额)也采用这种方式进行了重新设计。但是很快我意识到我的代码成为该特定数据结构的奴隶。例如,如果我有一个VolatilitySeries建议,那么我就不能有一个list,或一个tuple(或假设您熟悉Python)DataFrame波动性项目。这让我感到困扰,因为那时我的体系结构无法很好地扩展,并且一段时间后收益逐渐消失。这就是让我来这里的原因:)。
拉玛努伊·拉尔

另一个问题是,没有什么可以阻止任何人编写类似的代码volatilitySeries[0] + 3.0,这将是错误的。一旦您从中提取值VolatilitySeries,就可以发疯,因此安全只是短暂的。在人们并不总是知道所使用的确切类的多态环境中,这是很有可能的。而且您知道,您只能对用户进行如此多的教育。我知道您会说,嘿,如果我退出系统Volatility.value,我也可以做同样的事情,但是您知道,至少用户现在知道他正在使用特殊值。
Ramanuj Lal 2013年

有些人可能会建议重写所有从Seriesin中继承的常规函数VolatilitySeries,但这会破坏整个目的。因此,我从那条道路上学到的东西是,VolatilitySeries如果单个单元格是类型长的,那么从长远来看,拥有一个对象才真正可行Volatility
Ramanuj Lal 2013年

@RamanujLal:我对python不够了解,无法确定这种VolatileSeries方法是否可行。如果您已经尝试过了,但没有成功,那么您就很难在安全性和速度之间做出选择。我们不能在那里为您服务。(除非别人有一个很好的答案)
Bart van Ingen Schenau 2013年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.