Buffern nur wie ?

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
patmaster
User
Beiträge: 106
Registriert: Donnerstag 3. Februar 2011, 17:21

Hi,

Folgendes Problem habe ich zu lösen.
Ich muss ein directory überwachen und wenn sich etwas tut einen entsprechen Eintrag in einer DB machen.

Das überwachen ist kein Problem, das habe ich schon mit pywin32 implementiert.
Nun will ich aber nicht blind links für jede Änderung sofort einen Eintrag in die DB machen sondern nur, sagen wir alle 5 Minuten, um nicht wenn jemand innerhalb von 5 Minuten das gleiche file ändert, 5 Einträge zu haben sondern eben 1.
Ich habe mir gedacht ich löse das Ganze mit einem dict. Als key verwende ich den filenamen und als value eine Liste mit den Infos die ich so brauche, wie Pfad und welche Art von Änderung (Change, Del, Ren, usw.).
Also 1 Thread überwacht ständig das Filesystem und ein 2. schreibt alle 5 Minuten, pro Eintrag in dem dict. einen Eintrag in eine DB.
Nun muss ich das dict natürlich nach jedem DB-Update leeren und dabei aufpassen das ich nicht etwas entferne das es nie in die DB geschafft hat.

Beispiel: Ich habe ein file test.txt das sich ändert. Nun schreibe ich das in die DB. Während dessen ändert sich das file noch mal und damit auch der Wert zum entsprechenden key in meinem dict. Wenn ich nach dem DB Update den Eintrag im dict also einfach lösche verliere ich vlt. eine Aktion.

Wie kann ich das verhindern ?

Ist es sauber einfach das dict in eine 2. Variable zu kopieren die ich dem 2. thread übergebe und dann das ursprüngliche dict zu leeren ?

Ich könnte da vermutlich irgendetwas zusammen basteln, aber ich würde doch gerne wissen wie man das sauber lösen könnte :)

Vielen Dank schon mal an die die bis hier her gelesen haben und für die Hilfe :)

PS: Ich erwarte hier natürlich keinen fertigen Code. Ich will nur eine Umschreibung bzw Tipps, oder Schlagwörter.
lunar

@patmaster Verwende kein thread-übergreifendes Wörterbuch. Implementiere stattdessen das klassische Producer-Consumer-Muster.

Der Monitoring-Thread fügt bei jeder Änderung ein entsprechendes Objekt (z.B. ein "namedtuple()") in eine Warteschlange ein (siehe "Queue").

Der für die DB zuständige Thread entnimmt mittels "Queue.get()" jedes dieser Objekte aus der Warteschlange, und hält einen lokalen, sprich nur diesem Thread bekannten, Puffer vor. Dazu kannst Du ein Wörterbuch verwenden, welches Dateinamen auf die Art der Änderung abbildet. Zusätzlich merkt sich dieser Thread den Zeitpunkt des letzten Schreibzugriffs auf die Datenbank. Bei jeder Entnahme eines Objekts wird dann die aktuelle Zeit mit diesem Zeitstempel verglichen. Ist die Differenz größer als das gewünschte Puffer-Interval, wird der Puffer in die Datenbank geschrieben und geleert. Anschließend wird der Zeitstempel auf die aktuelle Zeit gesetzt. Achte dabei darauf, beim Aufruf von "Queue.get" den "timeout"-Parameter auf das Puffer-Interval zu setzen, damit der Thread den Puffer nicht übermäßig lange gefüllt hält, wenn über einen längeren Zeitraum keine Änderungen mehr eintreffen.

Ist das Schreiben in die Datenbank zu langsam, dann kannst Du diese in einen dritten Thread auslagern. Der puffernde Thread schreibt dann nicht direkt in die Datenbank, sondern fügt jedes Mal, wenn der Puffer geleert werden muss, die akkumulierten Änderungen in eine zweite Queue ein. Aus dieser entnimmt dann der dritte Thread seine Schreibaufträge für die Datenbank.
patmaster
User
Beiträge: 106
Registriert: Donnerstag 3. Februar 2011, 17:21

Danke für die ausführliche Erklärung. Ich hatte eigentlich vor das mit Locks zu machen, aber Queue sceint wohl wirklich sinnvoller.

Nachdem ich das 1. Mal mit Thread Synchronisierung zu tun hab werde ich vermutlich so emine Probleme haben, also den Thread bitte noch nicht schließen :)
lunar

@patmaster Wir schließen hier generell keine Threads :)
Antworten