Ich arbeite an einer .NET 4.0-Anwendung, die eine ziemlich teure Berechnung für zwei Doubles durchführt, die ein Double zurückgeben. Diese Berechnung wird für jedes von mehreren tausend Elementen durchgeführt . Diese Berechnungen werden in Task
einem Threadpool-Thread ausgeführt.
Einige vorläufige Tests haben gezeigt, dass dieselben Berechnungen immer wieder durchgeführt werden, daher möchte ich n Ergebnisse zwischenspeichern. Wenn der Cache voll ist, möchte ich das am wenigsten häufig verwendete Element wegwerfen . ( Bearbeiten: Ich habe festgestellt, dass es am seltensten keinen Sinn macht, denn wenn der Cache voll ist und ich ein Ergebnis durch ein neu berechnetes ersetzen würde, würde dieses am seltensten verwendet und beim nächsten Berechnen eines neuen Ergebnisses sofort ersetzt und zum Cache hinzugefügt)
Um dies zu implementieren, dachte ich darüber nach, eine Dictionary<Input, double>
(wo Input
eine Miniklasse wäre, in der die beiden Eingabedoppelwerte gespeichert werden) zu verwenden, um die Eingaben und die zwischengespeicherten Ergebnisse zu speichern. Ich müsste jedoch auch nachverfolgen, wann ein Ergebnis das letzte Mal verwendet wurde. Dafür würde ich wahrscheinlich eine zweite Sammlung benötigen, in der die Informationen gespeichert sind, die ich benötige, um ein Ergebnis aus dem Diktat zu entfernen, wenn der Cache voll ist. Ich bin besorgt, dass eine ständige Sortierung dieser Liste die Leistung beeinträchtigen würde.
Gibt es eine bessere (dh performantere) Möglichkeit, dies zu tun, oder vielleicht sogar eine gemeinsame Datenstruktur, die mir nicht bekannt ist? Welche Art von Dingen sollte ich profilieren / messen, um die Optimalität meiner Lösung zu bestimmen?
quelle
Angesichts der Rechenleistung, die Ihnen in einem durchschnittlichen PC zur Verfügung steht, scheint dies ein großer Aufwand für eine einzelne Berechnung zu sein. Außerdem haben Sie immer noch die Kosten für den ersten Aufruf Ihrer Berechnung für jedes eindeutige Wertepaar, sodass 100.000 eindeutige Wertepaare immer noch mindestens n * 100.000 Zeit kosten . Bedenken Sie, dass der Zugriff auf Werte in Ihrem Wörterbuch wahrscheinlich langsamer wird, wenn das Wörterbuch größer wird. Können Sie garantieren, dass die Zugriffsgeschwindigkeit Ihres Wörterbuchs ausreicht, um eine angemessene Rendite gegenüber der Geschwindigkeit Ihrer Berechnung zu erzielen?
Unabhängig davon klingt es so, als müssten Sie wahrscheinlich überlegen, wie Sie Ihren Algorithmus optimieren können. Dazu benötigen Sie ein Profiling-Tool wie Redgate Ants, um festzustellen, wo die Engpässe liegen, und um festzustellen, ob es Möglichkeiten gibt, den Overhead zu reduzieren, den Sie möglicherweise im Zusammenhang mit Klasseninstanziierungen, Listenüberquerungen und Datenbanken haben Zugriffe oder was auch immer Sie so viel Zeit kostet.
quelle
Ein Gedanke ist, warum nur Cache n Ergebnisse? Selbst wenn n 300.000 ist, würden Sie nur 7,2 MB Speicher verwenden (zuzüglich aller zusätzlichen Daten für die Tabellenstruktur). Das setzt natürlich drei 64-Bit-Doubles voraus. Sie können Memoization einfach auf die komplexe Berechnungsroutine selbst anwenden, wenn Sie nicht befürchten, dass Ihnen der Speicherplatz ausgeht.
quelle
Der Ansatz mit der zweiten Sammlung ist in Ordnung. Es sollte sich um eine Prioritätswarteschlange handeln , mit der Min-Werte schnell gefunden / gelöscht und Prioritäten innerhalb der Warteschlange geändert (erhöht) werden können (letzterer Teil ist der schwierige Teil, der von den meisten einfachen Implementierungen der Prio-Warteschlange nicht unterstützt wird). Die C5-Bibliothek hat eine solche Sammlung, heißt sie
IntervalHeap
.Oder natürlich können Sie versuchen, Ihre eigene Sammlung aufzubauen, so etwas wie eine
SortedDictionary<int, List<InputCount>>
. (InputCount
muss eine Klasse sein, die IhreInput
Daten mit IhremCount
Wert kombiniert )Das Aktualisieren dieser Sammlung beim Ändern Ihres Zählwerts kann durch Entfernen und erneutes Einfügen eines Elements implementiert werden.
quelle
Wie in der Antwort von Peter Smith ausgeführt, wird das Muster, das Sie implementieren möchten, als Memoisierung bezeichnet . In C # ist es ziemlich schwierig, Memoization auf transparente Weise ohne Nebenwirkungen zu implementieren. Oliver Sturms Buch über funktionale Programmierung in C # bietet eine Lösung (der Code steht zum Download zur Verfügung, Kapitel 10).
In F # wäre es viel einfacher. Natürlich ist es eine große Entscheidung, eine andere Programmiersprache zu verwenden, aber es kann sich lohnen, darüber nachzudenken. Insbesondere bei komplexen Berechnungen ist das Programmieren einfacher als das Auswendiglernen.
quelle