Die C ++ - Sprache bietet allgemeine Programmierung und Metaprogrammierung über Vorlagen. Diese Techniken haben ihren Weg in viele große wissenschaftliche Computerpakete (z. B. MPQC , LAMMPS , CGAL , Trilinos ) gefunden. Aber was haben sie tatsächlich dazu beigetragen, dass das wissenschaftliche Rechnen einen Wert hat, der über nicht generische Nicht-Metasprachen wie C oder Fortran hinausgeht, und zwar in Bezug auf die Gesamtentwicklungszeit und die Verwendbarkeit für gleiche oder angemessene Effizienz?
Hat die generische und Metaprogrammierung mithilfe von C ++ - Vorlagen bei einer wissenschaftlichen Rechenaufgabe eine Verbesserung der Produktivität, Expressivität oder Benutzerfreundlichkeit gezeigt, gemessen an gut bekannten Benchmarks (Codezeilen, Personalaufwand usw.)? Welche Risiken sind dementsprechend mit der Verwendung von C ++ - Vorlagen für die generische und Metaprogrammierung verbunden?
quelle
Antworten:
Ich denke, im Großen und Ganzen hat sich die Template-Metaprogrammierung in der Praxis als unbrauchbar erwiesen - sie kompiliert zu langsam und die Fehlermeldungen, die wir erhalten, sind einfach nicht zu entziffern. Auch bei der Metaprogrammierung ist die Eintrittsbarriere für Einsteiger einfach zu hoch.
Natürlich ist die generische Programmierung ein völlig anderes Thema, wie Trilinos, deal.II (meine eigene Bibliothek), DUNE und viele andere Bibliotheken bezeugen. und die Community hat es weitgehend akzeptiert, solange es sich in Grenzen hält, die die Probleme der Metaprogrammierung vermeiden. Ich denke, generisches Programmieren ist ein offensichtlicher Erfolg.
Natürlich ist keines dieser Themen unmittelbar mit OOP verbunden. Ich würde sagen, OOP wird von der wissenschaftlichen Computergemeinschaft allgemein akzeptiert. Auch wenn es sich nicht um generisches Programmieren handelt, ist es kein Thema der Debatte: Jede erfolgreiche Bibliothek, die in den letzten 15 Jahren geschrieben wurde (ob in C ++, C oder Fortran), verwendet OOP-Techniken.
quelle
Lassen Sie mich ein Beispiel geben, das auf Erfahrung basiert. Die meisten Bibliotheken, die ich von Tag zu Tag benutze, verwenden in irgendeiner Weise OOP. OOP ist in der Lage, die Komplexität zu verbergen, die für viele Domänen erforderlich ist. Es ist kein Mechanismus, der wirklich zur Leistung beiträgt. Was passieren kann, ist, dass eine Bibliothek bestimmte Optimierungen basierend auf der Objekthierarchie verwenden kann, aber zum größten Teil geht es darum, die Komplexität vor dem Benutzer zu verbergen. Nachschlagen von Entwurfsmustern. Dies sind die Mechanismen, die häufig eingesetzt werden, um diese Komplexität zu verbergen.
Nehmen Sie als Beispiel PETSc. PETSc verwendet ein Inspector / Executor-Modell von OOP, bei dem einer seiner Algorithmen die verfügbaren Routinen in einem bestimmten Objekt untersucht und auswählt, welche zur Ausführung der Routine ausgeführt werden sollen. Dies ermöglicht es einem Benutzer, Bedenken zu trennen, zum Beispiel kann die Matrixaktion jede Art von blockierter oder optimierter Routine enthalten und von zahlreichen iterativen Lösern effektiv verwendet werden. Indem der Benutzer die Möglichkeit erhält, seine eigenen Datentypen und Auswertungen anzugeben, werden einige wichtige Routinen beschleunigt und die gesamte Funktionalität der Bibliothek bleibt weiterhin verfügbar.
Ein weiteres Beispiel ist FEniCS und deal.II. Beide Bibliotheken verwenden OOP, um eine große Anzahl von Finite-Elemente-Methoden zu verallgemeinern. In beiden ist alles von Elementtyp, Elementreihenfolge, Quadraturdarstellung usw. austauschbar. Obwohl beide Bibliotheken "langsamer" sind als einige speziell strukturierte FEM-Codes, können sie eine Vielzahl von Problemen lösen, wobei ein Großteil der Komplexität von FEM dem Benutzer unbekannt ist.
Mein letztes Beispiel ist Elemental. Elemental ist eine neue Bibliothek für dichte lineare Algebra, die die Verwaltung von MPI-Kommunikatoren und der Datenposition zu einem sehr einfachen Sprachkonstrukt gemacht hat. Das Ergebnis ist, dass Sie, wenn Sie einen FLAME-Seriencode haben, durch Ändern der Datentypen auch einen Parallelcode über Elemental erhalten können. Noch interessanter ist, dass Sie mit der Datenverteilung spielen können, indem Sie die Verteilung gleich einer anderen einstellen.
OOP sollte als ein Weg betrachtet werden, die Komplexität zu managen, und nicht als Paradigma für den Wettbewerb mit handgewalzten Baugruppen. Auch wenn Sie es schlecht machen, entsteht viel Overhead. Daher müssen Sie das Timing beibehalten und die Mechanismen aktualisieren, mit denen Sie es verwenden.
quelle
Was Sprachfunktionen
OOP
für das wissenschaftliche Rechnen tun, sind kompaktere Code-Anweisungen, die das Verständnis und die Verwendung von Code verbessern. Beispielsweise müssenFFT
Routinen eine große Anzahl von Argumenten für jeden Funktionsaufruf enthalten, was den Code umständlich macht.Durch die Verwendung von
module
oderclass
-Anweisungen kann nur das übergeben werden, was zum Zeitpunkt des Aufrufs benötigt wird, da sich die restlichen Argumente auf die Problemeinrichtung beziehen (dh Größe der Arrays und Koeffizienten).Nach meiner Erfahrung hatte ich
SUBROUTINE
Aufrufe mit 55 Argumenten (rein und raus) und reduzierte diese auf 5, um den Code besser zu machen.Das ist Wert.
quelle
Ich bin ein starker Befürworter der generischen Programmierung und der Metaprogrammierung für das wissenschaftliche Rechnen. Ich entwickle gerade eine freie Software-C ++ - Bibliothek für Galerkin-Methoden, die auf diesen Techniken basiert und Feel ++ (http://www.feelpp.org) heißt und stetig an Fahrt gewinnt. Es stimmt, dass es immer noch Schwierigkeiten gibt, wie langsame Kompilierungszeiten und dass die Lernkurve steil sein kann, wenn man verstehen will, was sich hinter den Kulissen abspielt. Dies ist jedoch äußerst interessant und umwerfend. Wenn Sie auf Bibliotheksebene arbeiten und die Komplexität hinter einer domänenspezifischen Sprache verbergen, erhalten Sie ein äußerst leistungsfähiges Tool. Wir verfügen über ein sehr breites Spektrum an Methoden, die wir anwenden und vergleichen können. Für Lehrzwecke des wissenschaftlichen Rechnens ist dies fantastisch, für die Forschung und auch für neue numerische Methoden, für Anwendungen in großem Maßstab. na wir arbeiten dran aber soweit so gut, können wir schon ein paar nette sachen machen. Wir haben Ingenieure, Physiker und Mathematiker, die es benutzen: Die meisten benutzen nur die Sprache für die Variationsformulierung und sie sind damit zufrieden. Wenn ich einige Formulierungen betrachte, die unsere Physikerkollegen manipulieren, würde ich nicht wollen, dass sie "von Hand" ohne eine Hochsprache zur Beschreibung der Variationsformulierung gemacht werden. Ich persönlich bin der Meinung, dass diese "Techniken" oder "Paradigmen" jetzt notwendig sind, um die Komplexität von wissenschaftlichem Computercode zu bewältigen, indem die Codegröße mit einem riesigen Faktor multipliziert werden muss. Möglicherweise muss die Unterstützung der Metaprogrammierung in C ++ verbessert werden, aber sie ist bereits in gutem Zustand, insbesondere seit C ++ 11.
quelle
Möglicherweise finden Sie das Dokument http://arxiv.org/abs/1104.1729, das für Ihre Frage relevant ist. Es werden Ausdrucksvorlagen (eine bestimmte Anwendung der Metaprogrammierung von Vorlagen, die im wissenschaftlichen Code verwendet wird) aus der Perspektive der Leistung erörtert.
quelle
Vorlagen sind sehr gut darin, Typ- / Domänenprüfungen zur Laufzeit zu entfernen. Diese können zum Zeitpunkt der Kompilierung erledigt werden. Dies kann theoretisch die Leistung gegenüber derselben Art der Implementierung in C oder Fortran steigern, bei der die Typprüfung nur zur Laufzeit durchgeführt werden kann. Überprüfungen werden im Quellcode implementiert. Sie können jedoch mit Precompiler-Optionen dieselben Ergebnisse in C erzielen, diese müssen jedoch im Gegensatz zu Vorlagen von Hand ausgeführt werden.
Vorlagen können jedoch auch einen erheblichen Overhead verursachen. Sie können häufig Code Bloat erzeugen, was sich auf die Verwendung des Anweisungs-Cache auswirken kann. Darüber hinaus können generische Ansätze den Compiler bei der Optimierung oft in Schwierigkeiten bringen - bei der Verwendung generischer Ansätze ist die Codeanalyse nicht immer einfach. Es ist immer ein Problem mit der Automatisierung - einschließlich der Compileroptimierung -, sehr oft ist der Ausgabecode nicht cachefreundlich.
Die Vorteile der Typ- / Domänenprüfung sind zwar sicherer, aber der einzige wirkliche Vorteil, den ich in Bezug auf die Leistung sehe, und diese sind normalerweise nicht wahrnehmbar. Aber wie gesagt, der Gesamteffekt kann negativ sein, je nachdem, was Sie tun. Aus diesem Grund ist es oft besser, Ihren Code von Hand zu optimieren, wenn Sie erhebliche Engpässe haben.
quelle