【发布时间】:2013-06-04 11:43:50
【问题描述】:
我在面向对象和基于矢量的设计之间纠结。我喜欢物体赋予整个建筑的能力、结构和安全性。但与此同时,速度对我来说非常重要,在数组中包含简单的浮点变量确实有助于基于向量的语言/库,如 Matlab 或 Python 中的 numpy。
这是我写的一段代码来说明我的观点
问题:添加 Tow 波动率数字。如果 x 和 y 是两个波动率数字,则波动率之和为 (x^2 + y^2)^0.5(假设某些数学条件,但这在这里并不重要)。
我想非常快地执行此操作,同时我需要确保人们不会以错误的方式(x+y)添加波动率。这两点都很重要。
基于 OO 的设计是这样的:
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 中的 Series 是一种带有索引的列表) 现在我想添加两个:
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,但向量方法实在是太快了!有没有一种我可以同时获得的设计?我相信你们中的很多人都遇到过类似的设计选择,你们是怎么解决的?
这里的语言选择无关紧要。我知道你们中的很多人会建议使用 C++ 或 Java,而且代码可能比基于向量的语言运行得更快。但这不是重点。我需要使用 Python,因为我有许多其他语言没有的库。那是我的约束。我需要在其中进行优化。
而且我知道,很多人会建议并行化,gpgpu 等。但我想首先最大化单核性能,然后我可以并行化两个版本的代码。
提前致谢!
【问题讨论】:
-
那么,问题是什么?你能同时获得 OOP 和速度吗?不,这是一个权衡。
-
您的代码不起作用--
AttributeError: 'int' object has no attribute 'value'...我不完全确定您的问题是什么。您是否考虑过拥有将 numpy ndarrays 保存为.values 的Volatility对象? -
所以定义一个名为
VolatilityVector(或其他)的类,它包含一个值向量,根据需要定义这些东西的加法。瞧? -
顺便说一句,
map()看起来真的很丑而且它比生成器表达式慢。如果速度是您关心的问题,您应该使用例如(2.0*x-1.0 for x in range(0,n))代替。此外,如果您迫切需要速度,就像在 CPython 中一样,您应该在 C 中编写和优化关键部分。 -
@Evpok: 1. 你是对的,但是那部分代码没有包含在时间计算中。如果你仔细看,它只是已经描述的附加部分(相当粗略)。 2. 你关于使用 CPython 的想法当然是正确的,但是如果我开始用 C 编写“关键部分”,我最终会编写 Python 自己提供的大部分复杂算法。正如我所提到的,我需要在 Python 中工作。
标签: python performance oop numpy vectorization