Język C ++ zapewnia ogólne programowanie i metaprogramowanie za pomocą szablonów. Techniki te znalazły zastosowanie w wielu dużych komputerowych pakietach naukowych (np. MPQC , LAMMPS , CGAL , Trilinos ). Ale co w rzeczywistości przyczynili się do obliczeń naukowych, które wykraczają poza nie-ogólne, niemetaliczne języki, takie jak C lub Fortran, pod względem całkowitego czasu opracowywania i użyteczności dla równej lub odpowiedniej wydajności?
Biorąc pod uwagę naukowe zadanie obliczeniowe, czy ogólne i metaprogramowanie za pomocą szablonów C ++ wykazało poprawę wydajności, ekspresji lub użyteczności mierzoną za pomocą dobrze zrozumiałych testów porównawczych (linii kodu, nakładu pracy itp.)? Odpowiednio, jakie ryzyko wiąże się ze stosowaniem szablonów C ++ do generycznego i metaprogramowania?
źródło
Odpowiedzi:
Wydaje mi się, że metaprogramowanie szablonów okazało się w praktyce niemożliwe do użycia - kompiluje się zbyt wolno, a otrzymywane komunikaty o błędach są po prostu niemożliwe do odczytania. Bariera wejścia dla nowoprzybyłych jest również zbyt wysoka w przypadku korzystania z metaprogramowania.
Oczywiście, ogólne programowanie to zupełnie inna kwestia, o czym świadczą Trilinos, deal.II (moja własna biblioteka), DUNE i wiele innych bibliotek - wyrażanie tej samej koncepcji działającej na różnych typach danych jest czymś oczywistym, i społeczność w dużej mierze zaakceptowała to, o ile pozostaje w granicach, które pozwalają uniknąć problemów związanych z metaprogramowaniem. Myślę, że ogólne programowanie kwalifikuje się jako oczywisty sukces.
Oczywiście żaden z tych tematów nie jest natychmiast związany z OOP. Powiedziałbym, że OOP jest powszechnie akceptowane przez naukową społeczność komputerową. Nawet mniej niż ogólne programowanie, nie jest to temat debaty: każda udana biblioteka napisana w ciągu ostatnich 15 lat (napisana w C ++, C lub Fortran) korzysta z technik OOP.
źródło
Podam przykład oparty na doświadczeniu. Większość bibliotek, z których korzystam na co dzień, korzysta w pewien sposób z OOP. OOP jest w stanie ukryć złożoność wymaganą dla wielu domen, nie jest to mechanizm, który naprawdę pomaga w wydajności. Może się zdarzyć, że biblioteka będzie w stanie wykorzystywać określone optymalizacje oparte na hierarchii obiektów, ale w większości chodzi o ukrywanie złożoności przed użytkownikiem. Spójrz w górę Wzory projektowe, są to mechanizmy często stosowane w celu ukrycia tej złożoności.
Weźmy PETSc jako przykład. PETSc wykorzystuje model inspektora / modułu wykonawczego OOP, w którym dowolny z jego algorytmów analizuje dostępne procedury w danym obiekcie i wybiera, które wykonać, aby wykonać procedurę. Pozwala to użytkownikowi rozdzielić problemy, na przykład działanie matrycy może obejmować dowolny rodzaj zablokowanej lub zoptymalizowanej procedury i może być skutecznie wykorzystywane przez wiele iteracyjnych solverów. Dając użytkownikowi możliwość określania własnych typów danych i ocen, przyspiesza kilka ważnych procedur, a także udostępnia całą funkcjonalność biblioteki.
Innym przykładem, który podam, jest FEniCS i deal.II. Obie biblioteki używają OOP do uogólnienia na dużą liczbę metod elementów skończonych. Zarówno wszystko, od typu elementu, kolejności elementów, reprezentacji kwadratury itp. Jest wymienne. Chociaż obie te biblioteki są „wolniejsze” niż niektóre kody FEM o specjalnej strukturze, są w stanie rozwiązać wiele różnych problemów przy dużej złożoności MES nieznanej użytkownikowi.
Mój ostatni przykład to Żywiołak. Elemental to nowa gęsta biblioteka algebry liniowej, która podniosła trudność zarządzania komunikatorami MPI i lokalizacją danych w bardzo prostej konstrukcji językowej. W rezultacie, jeśli masz kod szeregowy FLAME, zmieniając typy danych, możesz również mieć kod równoległy za pośrednictwem elementu. Jeszcze bardziej interesujące możesz grać z dystrybucją danych, ustawiając dystrybucję równą innej.
OOP należy traktować jako sposób zarządzania złożonością, a nie paradygmat konkurowania z ręcznym walcowaniem. Również robienie tego źle spowoduje dużo narzutu, dlatego należy stale mierzyć czas i aktualizować mechanizmy, z których korzystają.
źródło
Jakie funkcje językowe
OOP
robią dla obliczeń naukowych, tworzą bardziej zwięzłe instrukcje kodu, co pomaga w lepszym zrozumieniu i korzystaniu z kodu. Na przykładFFT
procedury muszą zawierać dużą liczbę argumentów dla każdego wywołania funkcji, co powoduje, że kod jest kłopotliwy.Za pomocą instrukcji
module
lubclass
instrukcji można przekazać tylko to, co jest potrzebne w momencie wywołania, ponieważ pozostałe argumenty dotyczą konfiguracji problemu (tj. Rozmiaru tablic i współczynników).Z mojego doświadczenia
SUBROUTINE
wynika , że miałem wywołania z 55 argumentami (in & out) i zredukowałem to do 5, dzięki czemu kod jest lepszy.To jest wartość.
źródło
Jestem zdecydowanym zwolennikiem programowania ogólnego i metaprogramowania dla obliczeń naukowych. Właściwie tworzę bibliotekę wolnego oprogramowania C ++ dla metod Galerkina opartą na tych technikach o nazwie Feel ++ (http://www.feelpp.org), która stale nabiera tempa. To prawda, że nadal występują trudności, takie jak wolne czasy kompilacji i że krzywa uczenia się może być stroma, jeśli chce się zrozumieć, co dzieje się za sceną. Jest to jednak niezwykle interesujące i oszałamiające. Jeśli zrobisz to na poziomie biblioteki i ukryjesz złożoność języka specyficznego dla domeny, otrzymasz niezwykle potężne narzędzie. Dysponujemy bardzo szeroką gamą metod stosowania i porównywania. Jest to świetny do nauczania celów obliczeń naukowych, do badań i nowych metod numerycznych, do zastosowań na dużą skalę, dobrze, pracujemy nad tym, ale jak dotąd tak dobrze, możemy już zrobić kilka fajnych rzeczy. Korzystają z niego inżynierowie, fizycy i matematycy: większość z nich używa języka do formułowania wariacyjnego i są z niego zadowoleni. Patrząc na niektóre formulacje, którymi manipulują nasi koledzy z fizyków, nie chciałbym, aby były wykonywane „ręcznie” bez wysokiego poziomu języka opisującego formułę wariacyjną. Osobiście uważam, że te „techniki” lub „paradygmaty” są teraz niezbędne do rozwiązania złożoności naukowego kodu komputerowego, z koniecznością pomnożenia rozmiaru kodu przez ogromny czynnik. Prawdopodobnie istnieje potrzeba poprawy obsługi metaprogramowania w C ++, ale jest ona już w dobrej formie, zwłaszcza od C ++ 11.
źródło
Możesz znaleźć artykuł http://arxiv.org/abs/1104.1729 odpowiedni dla twojego pytania. Omówiono szablony wyrażeń (szczególne zastosowanie metaprogramowania szablonów stosowanych w kodzie naukowym) z perspektywy wydajności.
źródło
Szablony są bardzo dobre w usuwaniu kontroli typu / domeny w czasie wykonywania. Można to załatwić w czasie kompilacji. Teoretycznie może to zwiększyć wydajność w porównaniu z tym samym typem implementacji w C lub Fortran, gdzie sprawdzanie typu można wykonać tylko w czasie wykonywania - kontrole są implementowane w kodzie źródłowym. Można jednak osiągnąć te same wyniki w C przy użyciu opcji prekompilatora, ale muszą one być wykonane ręcznie, w przeciwieństwie do szablonów.
Jednak szablony mogą również generować znaczne koszty ogólne. Często mogą tworzyć nadęty kod, który może wpływać na użycie pamięci podręcznej instrukcji. Co więcej, podejścia ogólne mogą często wiązać kompilator podczas optymalizacji - nie zawsze jest to proste do analizy kodu, gdy stosuje się podejścia ogólne. Jest to zawsze problem z automatyzacją - w tym optymalizacją kompilatora - bardzo często kod wyjściowy nie jest przyjazny dla pamięci podręcznej.
Zalety sprawdzania typu / domeny, choć z pewnością bezpieczniejsze, są jedyną prawdziwą korzyścią, jaką widzę pod względem wydajności, i są one zazwyczaj niezauważalne. Ale jak mówię, ogólny efekt może być negatywny w zależności od tego, co robisz. Dlatego często lepiej jest ręcznie zoptymalizować kod tam, gdzie występują znaczne wąskie gardła.
źródło