2009-07-20 3 views
0

Ich entwickle eine App, die sehr große Nachschlagetabellen verwendet, um mathematische Berechnungen zu beschleunigen. Die größte dieser Tabellen ist ein int [] mit ~ 10 Millionen Einträgen. Nicht alle Nachschlagetabellen sind int []. Zum Beispiel ist ein Wörterbuch mit ~ 200.000 Einträgen. Derzeit I erzeugen einmal in jeder Nachschlagtabelle (die einige Minuten in Anspruch nimmt) und serialisiert sie auf die Festplatte (mit Druck) unter Verwendung der folgenden Schnipsel:Speichern großer Nachschlagetabellen

int[] lut = GenerateLUT(); 
    lut.Serialize("lut"); 

wo Serialisieren wie folgt definiert ist:

public static void Serialize(this object obj, string file) 
    { 
     using (FileStream stream = File.Open(file, FileMode.Create)) 
     { 
      using (var gz = new GZipStream(stream, CompressionMode.Compress)) 
      { 
       var formatter = new BinaryFormatter(); 
       formatter.Serialize(gz, obj); 
      } 
     } 
    } 

The Ärger habe ich beim Starten der Anwendung, ist, dass die Deserialisierung dieser Nachschlagetabellen sehr lange dauert (über 15 Sekunden). Diese Art von Verzögerung wird den Benutzer verärgern, da die App unbrauchbar wird, bis alle Nachschlagetabellen geladen sind. Derzeit ist die Deserialisierung ist wie folgt:

 int[] lut1 = (Dictionary<string, int>) Deserialize("lut1"); 
    int[] lut2 = (int[]) Deserialize("lut2"); 
... 

wo Deserialize ist definiert als:

public static object Deserialize(string file) 
    { 
     using (FileStream stream = File.Open(file, FileMode.Open)) 
     { 
      using (var gz = new GZipStream(stream, CompressionMode.Decompress)) 
      { 
       var formatter = new BinaryFormatter(); 
       return formatter.Deserialize(gz); 
      } 
     } 
    } 

Zuerst dachte ich, es könnte die gzip-Komprimierung haben, dass die Verlangsamung verursacht wurde, aber entferne es abgeschöpft nur einige hundert Millisekunden von den Serialisierungs-/Deserialisierungsroutinen entfernt.

Kann jemand vorschlagen, die Ladezeiten dieser Nachschlagetabellen beim ersten Start der App zu beschleunigen?

Antwort

2

Erstens wird das Deserialisieren in einem Hintergrund-Thread verhindern, dass die App "hängt", während dies geschieht. Das allein reicht vielleicht aus, um sich um Ihr Problem zu kümmern.

Allerdings ist die Serialisierung und Deserialisierung (insbesondere von großen Wörterbüchern) im Allgemeinen sehr langsam. Abhängig von der Datenstruktur kann das Schreiben eines eigenen Serialisierungscodes dies erheblich beschleunigen, insbesondere wenn in den Datenstrukturen keine gemeinsamen Referenzen vorhanden sind.

Dies gesagt, je nach dem Verwendungsmuster von diesem, eine Datenbank könnte ein besserer Ansatz sein. Sie könnten immer etwas machen, das mehr datenbankorientiert ist, und die Nachschlagetabelle auf eine träge Weise aus der Datenbank aufbauen (dh eine Nachschlagefunktion sucht in der Nachschlagetabelle, aber wenn die Nachschlage nicht existiert, laden Sie sie aus der Datenbank und speichern Sie sie es in der Tabelle). Dies würde den Start sofort machen (zumindest in Bezug auf die LUT), und wahrscheinlich Lookups weiterhin ziemlich bissig halten.

0

Ich denke, der offensichtliche Vorschlag ist, sie in den Hintergrund zu laden. Sobald die App gestartet wurde, hat der Benutzer sein Projekt geöffnet und den gewünschten Vorgang ausgewählt. Es bleibt nicht viel von diesen 15 Sekunden, um zu warten.

+0

Ich stimme dem zu, aber es ist immer noch eine Art Workaround imo. In Bezug auf meine App ist die GUI einfach genug, dass ein Benutzer bereit ist, eine Berechnung in weniger als 5 Sekunden durchzuführen. Im Moment strebe ich Ladezeiten von 5 Sekunden oder weniger an (wobei die Nachschlagetabellen in weniger als 5 Sekunden im Hintergrund geladen werden). – snazzer

0

Wie viele Daten sprechen wir hier? Meiner Erfahrung nach dauert es ungefähr 20 Sekunden, um ein Gigabyte von der Festplatte in den Speicher zu lesen. Wenn Sie also mehr als ein halbes Gigabyte lesen, kommen Sie mit Sicherheit in Hardware-Einschränkungen.

Wenn die Datenübertragungsrate nicht das Problem ist, dauert die eigentliche Deserialisierung Zeit. Wenn Sie über genügend Arbeitsspeicher verfügen, können Sie alle Tabellen in Speicherpuffern laden (File.ReadAllBytes()) und dann aus einem Speicherstream deserialize. Dadurch können Sie bestimmen, wie viel Zeit für das Lesen benötigt wird und wie viel Zeit für die Deserialisierung benötigt wird.

Wenn die Deserialisierung viel Zeit in Anspruch nimmt, könnten Sie, wenn Sie mehrere Prozessoren haben, mehrere Threds generieren, um die Serialisierung parallel durchzuführen.Mit einem solchen System könnten Sie möglicherweise eine oder mehrere Tabellen deserialisieren, während Sie die Daten für eine andere Tabelle laden. Dieser Pipeline-Ansatz könnte dazu führen, dass Ihre gesamte Lade-/Deserialisierungszeit fast so schnell ist wie die Last.

+0

Die gesamten Daten auf der Festplatte der Nachschlagetabellen sind kleiner als 100 Megabyte, daher können Einschränkungen bei der Datenübertragung ausgeschlossen werden. – snazzer

0

Eine andere Option ist, Ihre Tabellen in, gut, Tabellen: echte Datenbanktabellen. Selbst eine Engine wie Access sollte eine ziemlich gute Leistung erbringen, da Sie für jede Abfrage einen eindeutigen Index haben. Jetzt muss die App nur noch Daten einlesen, wenn sie gerade verwendet wird, und selbst dann wird sie genau wissen, wo sie in die Datei schauen soll.

Dies könnte die tatsächliche Leistung ein bisschen niedriger machen, weil Sie eine Festplatte lesen müssen für jede Berechnung. Aber es würde die der App wahrgenommen Leistung viel besser machen, denn es gibt nie eine lange Wartezeit. Und so oder so, die Wahrnehmung ist wahrscheinlich wichtiger als die Realität.

0

Warum zip sie?

Festplatte ist größer als RAM.

Eine direkte binäre Lese sollte ziemlich schnell sein.