...ohne die ganze Datei einzulesen?
Wenn ja, wären sie so nett und würden den Code zeigen, wie das geht?
Kann man in Python eine Datei von Zeile n zu Zeile m einlesen...
Nein, kann man auch in keiner anderen Sprache. Du kannst bestenfalls abbrechen, wenn du genug Zeilen gelesen hast. Und zb die ersten Zeilen die ungewünscht sind verwerfen.
Wenn du sowas effizienter machen willst, nimm eine Zeitserien Datenbank. Oder sogar eine normale.
Wenn du sowas effizienter machen willst, nimm eine Zeitserien Datenbank. Oder sogar eine normale.
Dateiobjekte verhalten sich wie Iteratoren, d.h. beim Iterieren lassen sich die Zeilen mitzählen und man könnte z. B. nur die behalten, die einen interessieren. Die Verwendung von seek() wäre auch möglich, wenn der Dateiaufbau genau bekannt ist. Das ist bei Textdateien aber eher selten der Fall.
Das Perlmodul Tie::File bietet ein Interface, das in die Richtung geht und sich in der Benutzung so anfühlt (auch wenn es nicht so implementiert ist; intern wird da viel gecached und "rum-geseeked"). Allerdings habe ich so etwas noch für keine andere Sprache gesehen.
Das die da ein nettes Interface drüber gelegt haben mag ja sein. itertools.dropwhile und takewhile sind auch nett. Aber um die fundamentalen Wahrheiten der Filesystemabstraktion kommen die auch nicht rum. Dateien liest man im Block. Wenn man die an unbekannt langen Zeilen auftrennen will, muss man das machen. Bestenfalls kann man bisecten und seeken, das geht aber auch nur bei speziellen Daten.
Wie groß sind denn die Dateien? Lohnt es sich überhaupt?
Code: Alles auswählen
from itertools import islice
with open(filename) as lines:
relevant_lines = list(islice(lines, start, end))
Danke.
Die Frage hat sich jetzt erübrigt.
Ich habe jetzt die Performancebremse in unserem Projekt herausgefunden.
In einem Mockup Programm habe ich verschiedene Szenarien auf Laufzeit gemessen:
Als Quelle kommt diese Datei: https://www.cjoint.com/c/JCmrBtJBWj1. das Programm läuft auf einem Raspberry Pi 3.
Gesucht wird was gegen Ende der Datei...
Szenario 1: die Datei wird Zeile für Zeile eingelesen, und auf schiere Textübereinstimmung (das nur ind den in den Spalten [2:9] vorkommen kann) geprüft. Laufzeit: weniger als 700 ms.
Szenario 2: die Datei wird Zeile für Zeile eingelesen, der Text in den Spalten [2:9] wird nach datetime() konvertiert und mit > und < gegen zwei datetime() Grenzen geprüft: Laufzeit: ca. 8,8 s
Szenario 3: die Datei wird komplett in eine Liste eingelesen: Laufzeit 170 ms
Szenario 4: Szenario drei + Analyse der Liste auf Textübereinstimmung wie bei 1 : Laufzeit ca. 1 s
Szenario 5: Szenario drei + der Text in den Spalten [2:9] wird nach datetime() konvertiert und mit > und < gegen zwei datetime() Grenzen geprüft: Laufzeit: ca. 10 s.
Es wird mir langsam klar: die datetime() Konvertierungen* sind der Zeitdieb!
*
Die Lösung: wir müssen den Log überdenken und die Zeit dort im datetime Format abspeichern.
Die Frage hat sich jetzt erübrigt.
Ich habe jetzt die Performancebremse in unserem Projekt herausgefunden.
In einem Mockup Programm habe ich verschiedene Szenarien auf Laufzeit gemessen:
Als Quelle kommt diese Datei: https://www.cjoint.com/c/JCmrBtJBWj1. das Programm läuft auf einem Raspberry Pi 3.
Gesucht wird was gegen Ende der Datei...
Szenario 1: die Datei wird Zeile für Zeile eingelesen, und auf schiere Textübereinstimmung (das nur ind den in den Spalten [2:9] vorkommen kann) geprüft. Laufzeit: weniger als 700 ms.
Szenario 2: die Datei wird Zeile für Zeile eingelesen, der Text in den Spalten [2:9] wird nach datetime() konvertiert und mit > und < gegen zwei datetime() Grenzen geprüft: Laufzeit: ca. 8,8 s
Szenario 3: die Datei wird komplett in eine Liste eingelesen: Laufzeit 170 ms
Szenario 4: Szenario drei + Analyse der Liste auf Textübereinstimmung wie bei 1 : Laufzeit ca. 1 s
Szenario 5: Szenario drei + der Text in den Spalten [2:9] wird nach datetime() konvertiert und mit > und < gegen zwei datetime() Grenzen geprüft: Laufzeit: ca. 10 s.
Es wird mir langsam klar: die datetime() Konvertierungen* sind der Zeitdieb!
*
Code: Alles auswählen
i = 0
found_start = False
found_stop= False
size_of_lines = len(lines)
while i < size_of_lines:
line = lines[i]
if line[0:1] == "d":
log_line_time_str = line[2:9]
log_line_time = DateTime.strptime(log_line_time_str, '%H:%M:%S')
if log_line_time >= log_start_time and not found_start:
start_line = current_line
found_start = True
elif log_line_time <= log_stop_time and not found_stop:
stop_line = current_line
found_stop = True
i += 1
- DeaD_EyE
- User
- Beiträge: 1038
- Registriert: Sonntag 19. September 2010, 13:45
- Wohnort: Hagen
- Kontaktdaten:
Hast du die Laufzeit vom Start des Programms festgehalten oder nur in einem bestimmten Programmteil?
Beim Raspberry Pi sollte man auch beachten, dass der Zugriff auf die SD-Karte nicht gerade besonders schnell ist.
Je nachdem was alles importiert wird, kann sich der Start des eigentlichen Programms signifikant verzögern.
Prüfen kann man das auch:
Bei mir braucht z.B. der Webserver auf dem Raspberry Pi (fastapi + sqlalchemy + anderes) eine halbe Ewigkeit (10 - 15 Sekunden), bis der erste Request möglich ist.
Liegt einfach daran, dass ziemlich viele Zugriffe auf die SD-Karte stattfinden, weil ich so viel importiere.
Beim Raspberry Pi sollte man auch beachten, dass der Zugriff auf die SD-Karte nicht gerade besonders schnell ist.
Je nachdem was alles importiert wird, kann sich der Start des eigentlichen Programms signifikant verzögern.
Prüfen kann man das auch:
Code: Alles auswählen
python -X importtime programm.py
Bei mir braucht z.B. der Webserver auf dem Raspberry Pi (fastapi + sqlalchemy + anderes) eine halbe Ewigkeit (10 - 15 Sekunden), bis der erste Request möglich ist.
Liegt einfach daran, dass ziemlich viele Zugriffe auf die SD-Karte stattfinden, weil ich so viel importiere.
sourceserver.info - sourceserver.info/wiki/ - ausgestorbener Support für HL2-Server
In meinem Mock-Up habe ich genau die Laufzeit von verschiedene Programmteile separat gestoppt.
Das Einlesen der große Datei dauerte 165 ms, die darauf folgende Schleife mit
sind das Problem: Hier eiert Python zwischen sechs und acht Sekunden daran.
Das Einlesen der große Datei dauerte 165 ms, die darauf folgende Schleife mit
Code: Alles auswählen
log_mid_time = DateTime.strptime(log_mid_time_str, '%H:%M:%S')
log_stop_time = log_mid_time + TimeDelta(minutes=3)
log_start_time = log_mid_time + TimeDelta(minutes=-3)
log_file = log_path + log_date_str + '.log'
log_start_time_str = log_start_time.strftime('%H:%M:%S')
log_stop_time_str = log_stop_time.strftime('%H:%M:%S')
Da offensichtlich die Logs beeinflusst werden können und die Antwort sicher nicht lautet: "Zeit dort im datetime Format abspeichern", steht die Antwort bereits in Beitrag 2 dieses Threads.
Aber das sind noch so viele Beustellen offen, da würde ich mir um Zeit erst einmal Gedanken machen.
Aber das sind noch so viele Beustellen offen, da würde ich mir um Zeit erst einmal Gedanken machen.
Die Logs in menschlich lesbarer Form sind auch Teil der Aufgabe. Wäre einer Datenbank infrage gekommen, hätte ich mich bei deinem Beitrag schon bedankt.sparrow hat geschrieben: ↑Donnerstag 19. März 2020, 14:39 Da offensichtlich die Logs beeinflusst werden können und die Antwort sicher nicht lautet: "Zeit dort im datetime Format abspeichern", steht die Antwort bereits in Beitrag 2 dieses Threads.
Aber das sind noch so viele Beustellen offen, da würde ich mir um Zeit erst einmal Gedanken machen.
- DeaD_EyE
- User
- Beiträge: 1038
- Registriert: Sonntag 19. September 2010, 13:45
- Wohnort: Hagen
- Kontaktdaten:
Ich hab die Logdatei mal eingelesen. Ist schon erstaunlich wie langsam das ist 3.5 MiB zu verarbeiten (~800 ms auf einem schnellen PC).
Das Programm, dass in die Datei schreibt, kann ja auch noch eine zusätzliche Datei anlegen, wo die letzte Position z.B. der letzten 10 Datensätze ist.
Mit seek kann man dann einfach zur entsprechenden Position springen und dann über die Zeilen iterieren.
Das Programm, dass in die Datei schreibt, kann ja auch noch eine zusätzliche Datei anlegen, wo die letzte Position z.B. der letzten 10 Datensätze ist.
Mit seek kann man dann einfach zur entsprechenden Position springen und dann über die Zeilen iterieren.
sourceserver.info - sourceserver.info/wiki/ - ausgestorbener Support für HL2-Server
Im Moment ist das Problem, dass die Logdatei ein Jitter* aufweist, denn wir versuchen im Griff zu bekommen.
*Die Timestamps sind oft nicht in Folge, und zeigen Abweichungen von bis zu +- 3Sekunden.
Es ist -wohl gemerkt ein Jitter, kein Drift.
Der serielle Sender sendet absolut regelmäßig und der Langzeitgleichlauf ist nicht das Problem.
Aber die Verarbeitung in Python erfolgt (im Programm SerialPlotter, der die Log-Datei schreibt) machmal zeitverzögert.
Ob die Verzögerung in Python stattfindet oder vom Betriebsystem kommt, dass muss ich noch eruieren.
Ich hatte auch aus Performancegründen* den Python script mit "nice python" gestartet, weil noch andere wichtigere Tasks auf dem keinen Pi laufen müssen.
Das Ausgeben des Matplotlib Plots frisst 90% der Zeit eines Raspberry-Prozessors für 1 bis2 Sekunden.
Das erfolgt im Matplotlib Modul, das kann ich nicht ändern.....
Leider scheint das Threading von Python kein Prioritäten zu kennen.
Ist auch nicht preemptive.
https://github.com/Gordon999/Pi-Arduino_Ser_Plotter
*Die Timestamps sind oft nicht in Folge, und zeigen Abweichungen von bis zu +- 3Sekunden.
Es ist -wohl gemerkt ein Jitter, kein Drift.
Der serielle Sender sendet absolut regelmäßig und der Langzeitgleichlauf ist nicht das Problem.
Aber die Verarbeitung in Python erfolgt (im Programm SerialPlotter, der die Log-Datei schreibt) machmal zeitverzögert.
Ob die Verzögerung in Python stattfindet oder vom Betriebsystem kommt, dass muss ich noch eruieren.
Ich hatte auch aus Performancegründen* den Python script mit "nice python" gestartet, weil noch andere wichtigere Tasks auf dem keinen Pi laufen müssen.
Das Ausgeben des Matplotlib Plots frisst 90% der Zeit eines Raspberry-Prozessors für 1 bis2 Sekunden.
Das erfolgt im Matplotlib Modul, das kann ich nicht ändern.....
Leider scheint das Threading von Python kein Prioritäten zu kennen.
Ist auch nicht preemptive.
https://github.com/Gordon999/Pi-Arduino_Ser_Plotter
Selbstverstaendlich ist das Threading preemptive. Oder spickst du deinen Code mit "jetzt darf wer anders"-Aufrufen? Es ist allerdings durch das GIL niemals echt parallel. Und da die Threads von Python auch Systemthreads sind, kannst du sie grundsaetzlich auch priorisieren. ZB mit chrt, wenn man PREEMPT_RT benutzt. Durch die Interaktion mit dem GIL und dem Laufzeitverhalten des Intepreters ist der Vorteil allerdings relativ unklar. Dafuer gibt's dann eben multiprocessing.
Aber der Kernfehler ist konzeptioneller Art: wenn eure Zeitstempel auf dem PI genommen werden, obwohl die Daten vom Arduino kommen, dann ist das schon ungeschickt. Die muessen dort gezeitstempelt werden, und mit einem kleinen Filter bestimmt man relativen Offset und Drift, und kompensiert die Zeitstempel damit in Python. Dann ist es auch egal, wenn da mal ein paar Sekunden(bruchteile) mal nix passiert.
Aber der Kernfehler ist konzeptioneller Art: wenn eure Zeitstempel auf dem PI genommen werden, obwohl die Daten vom Arduino kommen, dann ist das schon ungeschickt. Die muessen dort gezeitstempelt werden, und mit einem kleinen Filter bestimmt man relativen Offset und Drift, und kompensiert die Zeitstempel damit in Python. Dann ist es auch egal, wenn da mal ein paar Sekunden(bruchteile) mal nix passiert.
Der Arduino (die Arduinos von viele, viele existierende Stationen In Europa) kennen keine Uhrzeit. Höchstens ein Sekundentick, der allerdings von nichts unterbrochen wird.
@RIN67630: wenn Dir die grundlegenden Kenntnisse, wie man so ein System aufbaut, fehlen, dann wird das schwierig. Man synchronisiert die Ticks des Arduino mit der Uhrzeit vom Raspi und ist so von der genauen Zeit, wann die Daten verarbeitet werden, unabhängig.
Dass jetzt das Aufnehmen von Daten und das Darstellen im selben Prozess laufen, ist mir neu.
Wie so oft, fehlt da die vollständige Information, was Du eigentlich machst.
Dass jetzt das Aufnehmen von Daten und das Darstellen im selben Prozess laufen, ist mir neu.
Wie so oft, fehlt da die vollständige Information, was Du eigentlich machst.
In Github ist alles vorhanden: Kurzbeschreibung, der Arduino Simulator zum testen, (nicht die echte Stationen, die zu viel Hardware erfordern würden) und SerielPlotter,py, LogPlotter.py, selbst mein Mock-up zum Testen...Sirius3 hat geschrieben: ↑Sonntag 22. März 2020, 21:20 @RIN67630: wenn Dir die grundlegenden Kenntnisse, wie man so ein System aufbaut, fehlen, dann wird das schwierig. Man synchronisiert die Ticks des Arduino mit der Uhrzeit vom Raspi und ist so von der genauen Zeit, wann die Daten verarbeitet werden, unabhängig.
Dass jetzt das Aufnehmen von Daten und das Darstellen im selben Prozess laufen, ist mir neu.
Wie so oft, fehlt da die vollständige Information, was Du eigentlich machst.
Lediglich steht dort nicht drin, dass ich nicht auf eine grüne Wiese aufbaue, sondern eine bestehende Landschaft von 600 Stationen um ein Plot und re-Plotfunktion erweitern möchte, weil die Software auch allgemein gehalten werden sollte.
Abgesehen davon, wäre es der völlig falschen Weg, den groben Jitter des Raspberry Pi auf dem Arduino zu übertragen, dort müssen Messungen mit verbindlichen Takten (125 ms, 1 s) verarbeitet werden.
Genau das tun wir ja auch: die Nachrichten mit einer feste Länge kommen exakt im Sekundentakt über die exklusiv genutzte serielle Schnittstelle Im Raspberry Pi hinein, somit ist die Synchronität bei /dev/ttyUSB0 gegeben.
Das Problem entsteht nicht an der Quelle, sondern dadurch, dass der Raspberry Pi (innerhalb des Python Programms SerialPlotter.py oder aufgrund von Verzögerungen im Betriebssystem, das weiß ich noch nicht) die Daten nur mit Jitter verarbeitet, dann gibt es halt den falschen Zeitstempel.
Eine mögliche Lösung könnte gegebenenfalls sein, die serielle Schnittstelle über ein getrenntes Prozess mit höherer Priorität abzufragen, nur den Zeitstempel hinzufügen und dann zum SerialPlotter.py zu pipen?
Wenn SerialPlotter.py dann nur noch mit Parkinson verarbeitet, würde es dann niemand mehr jucken. Ich glaube, im Audiobereich macht man es nicht anders...