Объектно-ориентированное и векторное программирование


14

Я разрываюсь между объектно-ориентированным и векторным дизайном. Я люблю способности, структуру и безопасность, которые объекты дают всей архитектуре. Но в то же время скорость очень важна для меня, и наличие простых переменных с плавающей точкой в ​​массиве действительно помогает в векторных языках / библиотеках, таких как Matlab или numpy в Python.

Вот фрагмент кода, который я написал, чтобы проиллюстрировать мою точку зрения.

Проблема: добавление значений волатильности буксировки. Если x и y - два числа волатильности, сумма волатильности равна (x ^ 2 + y ^ 2) ^ 0.5 (при условии определенного математического условия, но это здесь не важно).

Я хочу выполнить эту операцию очень быстро, и в то же время мне нужно убедиться, что люди не просто неправильно добавляют волатильность (х + у). Оба из них важны.

ОО-дизайн будет выглядеть примерно так:

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

(Помимо: опять же, Series в Python - это своего рода список с индексом) Теперь я хочу добавить два:

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

Просто добавление выполняется на моей машине за 3,8 секунды, результаты, которые я дал, вообще не включают время инициализации объекта, а только код добавления, который был рассчитан по времени. Если я запускаю то же самое, используя массивы:

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 раз быстрее!

Как вы можете видеть, способ ООП дает мне большую безопасность, так что люди не будут добавлять Волатильность неправильно, но векторный метод просто безумно быстр! Есть ли дизайн, в котором я могу получить оба? Я уверен, что многие из вас сталкивались с подобным выбором дизайна, как вы с этим справились?

Выбор языка здесь не имеет значения. Я знаю, что многие из вас посоветовали бы использовать C ++ или Java, и в любом случае код может работать быстрее, чем векторные языки. Но дело не в этом. Мне нужно использовать Python, потому что у меня есть множество библиотек, недоступных на других языках. Это мое ограничение. Мне нужно оптимизировать в нем.

И я знаю, что многие люди предложили бы распараллеливание, gpgpu и т. Д. Но я хочу сначала максимизировать производительность одного ядра, а затем я могу распараллелить обе версии кода.

Заранее спасибо!


3
Тесно связанный способ думать об этой проблеме: следует ли вам использовать структуру массивов (SoA) или массив структур (AoS) для производительности? С SoA стало проще векторизоваться, а AOS стал более дружественным к ООП на большинстве языков.
— Патрик

да @ Патрик, если вы видите первый ответ, я думаю, что Барт привел практический пример того, что вы делаете. Я прав? Я заметил, что вы говорите большинстве языков, так есть ли языки, в которых оба близки по производительности?
— Раманудж Лал

Ответы:


9

Как вы можете видеть, способ ООП дает мне большую безопасность, так что люди не будут добавлять Волатильность неправильно, но векторный метод просто безумно быстр! Есть ли дизайн, в котором я могу получить оба? Я уверен, что многие из вас сталкивались с подобным выбором дизайна, как вы с этим справились?

Дизайн больших объектов. У Pixelобъекта нет передышки для параллельного преобразования изображения или преобразования графического процессора или чего-то подобного. Действительно Image, при условии, что он не должен проходить через барьер крошечного Pixelобъекта, чтобы получить данные.


5

Это одна из тех областей, где невозможно дать однозначные ответы, потому что это касается компромисса. Как вы узнали, ни OO, ни Vector-based не всегда лучше, но все зависит от того, как будет использоваться программное обеспечение.

Вы можете попытаться объединить лучшее из обоих и создать как Volatilityобъект, так иVolatilitySeries объект, где второй концептуально представляет объекты серии изменчивости, но внутренне использует метод хранения, который гораздо лучше подходит для векторизации вычислений (структура массивов). , Тогда вам просто нужно научить своих пользователей, что использование VolatilitySeriesнамного предпочтительнее Series(Volatility).


Спасибо, Барт, это хорошая идея. На самом деле я пошел по этому пути в моем текущем проекте по частям, где некоторые объекты, такие как денежные суммы, были переработаны таким образом. Но вскоре я понял, что мой код становится рабом этой конкретной структуры данных. Например, если у меня есть, VolatilitySeriesкак вы предлагаете, то я не могу иметь list, tupleили (или (если вы знакомы с Python)) DataFrameэлементы волатильности. Это беспокоит меня, потому что тогда моя архитектура плохо масштабируется, и через некоторое время преимущества исчезают. И это то, что приводит меня сюда :).
— Раманудж Лал

Другая проблема заключается в том, что ничто не мешает кому-то написать подобный код volatilitySeries[0] + 3.0, что будет неправильно. Как только вы извлекаете значения VolatilitySeries, вы можете сходить с ума, поэтому безопасность недолговечна. В полиморфной среде, где люди не всегда знают, какой именно класс используется, это очень возможно. И вы знаете, вы можете только обучить своих пользователей так много. Я знаю, вы скажете, что, эй, я могу сделать то же самое, если выверну Volatility.value, но вы знаете, по крайней мере, пользователь теперь знает, что он использует специальное значение.
— Раманудж Лал

Некоторые могут также предложить переопределить все эти обычные функции, унаследованные от Seriesin VolatilitySeries, но это наносит ущерб всей цели. Итак, что я узнал из этого пути, так это то, что наличие VolatilitySeriesобъекта действительно работает в долгосрочной перспективе, только если отдельные ячейки имеют тип Volatility.
— Раманудж Лал

@RamanujLal: Я не знаю Python достаточно хорошо, чтобы определить, является ли VolatileSeriesподход жизнеспособным. Если вы уже попробовали это, и это не сработало, тогда вам приходится выбирать между безопасностью и скоростью. Мы не можем помочь вам там. (если у кого-то еще нет блестящего ответа)
— Барт ван Инген Шенау
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.