Ich entwickle eine Physiksimulation und da ich in der Programmierung noch nicht so weit bin, habe ich immer wieder Probleme beim Erstellen großer Programme (hauptsächlich Speicherprobleme). Ich kenne mich mit dynamischer Speicherzuweisung und -löschung (neu / löschen usw.) aus, benötige jedoch einen besseren Ansatz für die Strukturierung des Programms.
Angenommen, ich simuliere ein Experiment, das einige Tage lang ausgeführt wird, mit einer sehr hohen Abtastrate. Ich müsste eine Milliarde Proben simulieren und überfliegen.
Als supervereinfachte Version sagen wir, ein Programm nimmt die Spannungen V [i] und summiert sie in fünf:
dh NewV [0] = V [0] + V [1] + V [2] + V [3] + V [4]
dann ist NewV [1] = V [1] + V [2] + V [3] + V [4] + V [5]
dann ist NewV [2] = V [2] + V [3] + V [4] + V [5] + V [6] ... und das geht für eine Milliarde Abtastungen weiter.
Am Ende hätte ich V [0], V [1], ..., V [1000000000], wenn stattdessen die einzigen, die ich für den nächsten Schritt speichern müsste, die letzten 5 V [i] wären. s.
Wie würde ich einen Teil des Arrays löschen / freigeben, damit der Speicher wieder verwendet werden kann (sagen Sie V [0] nach dem ersten Teil des Beispiels, in dem er nicht mehr benötigt wird)? Gibt es Alternativen zur Strukturierung eines solchen Programms?
Ich habe von malloc / free gehört, aber gehört, dass sie nicht in C ++ verwendet werden sollten und dass es bessere Alternativen gibt.
Vielen Dank!
tldr; Was mache ich mit Teilen von Arrays (einzelnen Elementen), die nicht mehr benötigt werden und sehr viel Speicher beanspruchen?
V
einem neuen Array speichern . Grundsätzlich denke ich jedoch, dass Ihr Problem entweder in Ihren Algorithmen oder in Ihren Datenstrukturen liegt, und da wir keine Details haben, ist es schwierig zu wissen, wie man es effizient macht.Antworten:
Was Sie als "Glätten um fünf" bezeichnen, ist ein digitales Filter mit endlicher Impulsantwort (FIR). Solche Filter werden mit kreisförmigen Puffern implementiert. Sie behalten nur die letzten N Werte bei, Sie behalten einen Index in dem Puffer, der Ihnen sagt, wo sich der älteste Wert befindet, Sie überschreiben den aktuell ältesten Wert bei jedem Schritt mit dem neuesten und Sie schrittweise den Index jedes Mal.
Sie speichern Ihre gesammelten Daten, die Sie zerstören werden, auf der Festplatte.
Abhängig von Ihrer Umgebung ist dies möglicherweise einer der Orte, an denen Sie besser auf erfahrene Hilfe angewiesen sind. An einer Universität schreiben Sie im Fachbereich Informatik eine Notiz an die Pinnwand und bieten Studentenlöhne (oder sogar Beratungsgebühren für Studenten) für einige Stunden Arbeit an, damit Sie Ihre Daten besser verarbeiten können. Oder bieten Sie Undergraduate Research Opportunity-Punkte an? Oder so.
quelle
Jedes Problem kann durch Hinzufügen einer zusätzlichen Indirektionsebene gelöst werden. Also mach das.
Sie können einen Teil eines Arrays in C ++ nicht löschen. Sie können jedoch ein neues Array erstellen, das nur die Daten enthält, die Sie behalten möchten, und dann das alte Array löschen. So können Sie eine Datenstruktur erstellen, mit der Sie Elemente, die Sie nicht möchten, von vorne "entfernen" können. Eigentlich wird ein neues Array erstellt, und die nicht entfernten Elemente werden in das neue Array kopiert. Anschließend werden die alten Elemente gelöscht.
Oder du könntest einfach nutzen
std::deque
, was das schon effektiv kann.deque
, oder "Double-Ended Queue", ist eine Datenstruktur, die für Fälle vorgesehen ist, in denen Sie Elemente von einem Ende löschen, während Sie Elemente zum anderen hinzufügen.quelle
std::deque
ist der Weg zu gehendeque
. Das heißt, Speichern und Wiederverwenden von Zuordnungen nach Bedarf. Alsodeque
scheint eine vollkommen adäquate Lösung für das Problem zu sein.Die FIR- und SMA-Antworten, die Sie erhalten haben, sind in Ihrem Fall gut, aber ich möchte die Gelegenheit nutzen, um einen allgemeineren Ansatz voranzutreiben.
Was Sie hier sehen , ist ein Strom von Daten: statt Strukturierung Ihres Programms in drei großen Schritten (get Daten, Berechnung, Ausgabeergebnis) , die auf einmal alle Daten im Speicher erfordern Laden Sie stattdessen es als eine Struktur kann Pipeline .
Eine Pipeline beginnt mit einem Stream, wandelt ihn um und schiebt ihn in eine Senke.
In Ihrem Fall sieht die Pipeline folgendermaßen aus:
C ++ verwendet eher Iteratoren als Streams, doch um ehrlich zu sein, lassen sich Streams einfacher modellieren (es gibt einen Vorschlag für Bereiche, die Streams ähneln würden):
Und dann sieht die Pipeline so aus:
Streams sind nicht immer anwendbar (sie funktionieren nicht, wenn Sie zufälligen Zugriff auf die Daten benötigen), aber wenn sie es sind, rocken sie: Wenn Sie auf einer sehr kleinen Speicherkapazität arbeiten, behalten Sie alles im CPU-Cache.
Ein weiterer Hinweis: Es scheint, dass Ihr Problem "peinlich parallel" ist. Sie möchten Ihre große Datei möglicherweise in Blöcke aufteilen. und dann die Stücke parallel verarbeiten.
Wenn CPU der Engpass ist (und nicht E / A), können Sie ihn beschleunigen, indem Sie einen Prozess pro Kern starten, den Sie haben, nachdem Sie die Dateien in ungefähr gleichen Mengen aufgeteilt haben.
quelle