Jestem rozdarty między projektowaniem obiektowym a projektowaniem wektorowym. Uwielbiam umiejętności, strukturę i bezpieczeństwo, jakie obiekty dają całej architekturze. Ale jednocześnie szybkość jest dla mnie bardzo ważna, a posiadanie prostych zmiennych zmiennoprzecinkowych w tablicy naprawdę pomaga w językach / bibliotekach wektorowych, takich jak Matlab lub numpy w Pythonie.
Oto fragment kodu, który napisałem, aby zilustrować mój punkt widzenia
Problem: Dodanie liczb zmienności Holowania. Jeśli x i y są dwiema liczbami zmienności, suma zmienności wynosi (x ^ 2 + y ^ 2) ^ 0,5 (przy założeniu pewnego warunku matematycznego, ale tutaj nie jest to ważne).
Chcę wykonać tę operację bardzo szybko, a jednocześnie muszę upewnić się, że ludzie nie dodają po prostu zmienności w niewłaściwy sposób (x + y). Oba są ważne.
Projekt oparty na OO wyglądałby mniej więcej tak:
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))
(Poza tym: dla tych, którzy są nowicjuszami w Pythonie, __add__
jest tylko funkcja, która zastępuje +
operatora)
Załóżmy, że dodałem listy holownicze wartości zmienności
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)))
(Poza tym: znowu, seria w Pythonie jest rodzajem listy z indeksem) Teraz chcę dodać dwa:
t1 = datetime.now()
vs3 = vs1 + vs2
t2 = datetime.now()
print t2-t1
Po prostu dodawanie działa na mojej maszynie w 3,8 sekundy, podane przeze mnie wyniki w ogóle nie uwzględniają czasu inicjalizacji obiektu, jest to tylko kod czasowy, który został odmierzony. Jeśli uruchomię to samo za pomocą tablic 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
Działa za 0,03 sekundy. To ponad 100 razy szybciej!
Jak widać, metoda OOP daje mi dużo bezpieczeństwa, że ludzie nie będą dodawać Zmienności w niewłaściwy sposób, ale metoda wektorowa jest po prostu szalona szybko! Czy istnieje projekt, w którym mogę uzyskać oba? Jestem pewien, że wielu z was wpadło na podobne wybory projektowe, jak to się udało?
Wybór języka tutaj jest nieistotny. Wiem, że wielu z was radziłoby używać C ++ lub Java, a kod może i tak działać szybciej niż języki oparte na wektorze. Ale nie o to chodzi. Potrzebuję użyć Pythona, ponieważ mam wiele bibliotek niedostępnych w innych językach. To moje ograniczenie. Muszę w nim zoptymalizować.
I wiem, że wiele osób sugerowałoby równoległość, gpgpu itp. Ale najpierw chcę zmaksymalizować wydajność jednego rdzenia, a następnie mogę zrównoleglić obie wersje kodu.
Z góry dziękuję!
źródło
Odpowiedzi:
Projektuj większe obiekty.
Pixel
Obiekt nie ma miejsca dla oddychania i równoległego pętli lub przekształceń graficznych GPU lub coś podobnego. TakImage
, pod warunkiem, że nie musi przechodzić przez barierę małegoPixel
obiektu, aby uzyskać dostęp do danych.źródło
Jest to jeden z tych obszarów, w którym nie można udzielić ostatecznych odpowiedzi, ponieważ dotyczy kompromisu. Jak się dowiedziałeś, ani OO, ani oparte na wektorze nie zawsze są lepsze, ale wszystko zależy od tego, jak oprogramowanie będzie używane.
Możesz spróbować połączyć to, co najlepsze, i stworzyć zarówno
Volatility
obiekt, jak iVolatilitySeries
obiekt, gdzie drugi koncepcyjnie reprezentuje serię obiektów zmienności, ale wewnętrznie używa metody przechowywania, która jest znacznie lepiej dostosowana do wektoryzacji obliczeń (struktura tablic) . Następnie musisz tylko poinformować użytkowników, że korzystanie z nichVolatilitySeries
jest o wiele lepsze niż używanieSeries(Volatility)
.źródło
VolatilitySeries
jak sugerujesz, to nie mogę miećlist
,tuple
lub (zakładając, że znasz Python) aDataFrame
elementów zmienności. Niepokoi mnie to, ponieważ wtedy moja architektura nie skaluje się dobrze, a korzyści znikają po pewnym czasie. I to mnie tu sprowadza :).volatilitySeries[0] + 3.0
, co będzie błędne. Po wykręceniu wartościVolatilitySeries
możesz wpaść w szał, więc bezpieczeństwo trwa krótko. Jest to bardzo możliwe w środowisku polimorficznym, w którym ludzie nie zawsze zdają sobie sprawę z tego, jaką dokładnie klasę zastosowano. I wiesz, możesz tylko edukować swoich użytkowników. Wiem, że to powiesz, hej, ja też mogę zrobić to samo, jeśli się wykręcęVolatility.value
, ale wiesz, przynajmniej użytkownik wie teraz, że używa specjalnej wartości.Series
poVolatilitySeries
, ale to pokonuje cały cel. Tak więc nauczyłem się z tej ścieżki, że posiadanieVolatilitySeries
obiektu naprawdę działa na dłuższą metę tylko wtedy, gdy poszczególne komórki są typuVolatility
.VolatileSeries
podejście jest wykonalne. Jeśli już go wypróbowałeś i nie zadziałało, masz trudny wybór między bezpieczeństwem a prędkością. Nie możemy ci tam pomóc. (chyba że ktoś inny ma świetną odpowiedź)