Gleichzeitig mit mehreren Prozessen aus einem File lesen

Hallo,
ich habe ein kleine Nuss zu knacken:
Ich muss aus mehreren Prozessen aus dem gleichen File lesen. Das Problem ist, dass die gleichzeitigen Zugriffe und das nicht-atomare seek+read dazu führen, dass Schrott gelesen wird.
Dummerweise kann ich auch keine Funktionen aus dem Modul os verwenden, da es sich um einen Importer handelt – und os ist kein build-in Modul. damit kann ich also os.dup() ebenso wenig verwenden wie Semaphoren. Die Einzilge Lösung, die mit eingefallen ist, ist damit, das File bei jedem Lesezugriff neu zu öffnen.
Gibt es einen eleganteren /und effizienteren) Weg?
Hintergrund: Importer by PyInstaller: https://github.com/pyinstaller/pyinstaller/issues/1070

-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1
Hartmut Goebel wrote:
Hallo,
ich habe ein kleine Nuss zu knacken:
Ich muss aus mehreren Prozessen aus dem gleichen File lesen. Das Problem ist, dass die gleichzeitigen Zugriffe und das nicht-atomare seek+read dazu führen, dass Schrott gelesen wird.
Warum verwendest Du nicht für jeden Prozess ein eigenes Filehandle?
- -aj

Hallo Hartmut, wird das File während der Zugriffe verändert? Sind es viele Files und sind sie groß?
Selbst SSDs mögen wegen des seriellen SATA Interfaces sowas nicht so gerne, bzw. sind nicht darauf ausgelegt gleichzeitig im selben Block an verschiedenen Stellen zu orgeln.
Wenn also neben dem "Schrott" der ja auch an Festplatten-Limits liegen kann, das letzte Quentchen Performance zählt, versuchs mal mit einer RAM-Disk oder einem eigenen RAM-Cache. Leider heute oft vergessen aber so sauschnell, weil DMA es direkt in die Register schieben kann. Je nach Implementierung der RAM-Disk (es gibt verschiedene Möglickeiten) kann es auch lahm werden. Persistenz (wenn Du auch schreiben musst) ist auch ein Knackpunkt.
Üblicherweise können sich nicht ohne Weiteres mehrere getrennte Pyython Prozesse eine Fileressource optimiert teilen. Ein Filehandle von mehreren Prouzessen anzusprechen geht doch glaube ich garnicht. Der Haken sind doch eher die unkoordinierten Zugriffe auf das Filesystem (disk-trashing).
Vielleicht hilfts ja.
-- Armin
One last Thing: In Python ist ein String eine Liste aus Zeichen. Wenn Du also deine Datei wie eine Datenbank oder Liste bereitstellst, kannst du den Zugriff anders organisieren. Binäre Daten und schreibende Zugriffe und die Komplexität der Dateien/Struktur sind natürlich Knackpunkte die ich nicht kenne.
Am 13.03.2015 um 16:07 schrieb Andreas Jung lists@zopyx.com:
Signierter PGP Teil Hartmut Goebel wrote:
Hallo,
ich habe ein kleine Nuss zu knacken:
Ich muss aus mehreren Prozessen aus dem gleichen File lesen. Das Problem ist, dass die gleichzeitigen Zugriffe und das nicht-atomare seek+read dazu führen, dass Schrott gelesen wird.
Warum verwendest Du nicht für jeden Prozess ein eigenes Filehandle?
-aj
python-de maillist - python-de@python.org https://mail.python.org/mailman/listinfo/python-de
-- Armin Carl Stroß-Radschinski | developer@acsr.de | Twitter: @syncmitter Dipl. Designer FH | project-consultant | fon +49 171 21 94699 | IRC: acsr | Skype: astrossradschinski
ACSR industrialdesign | Armin Stroß-Radschinski Landgrafenstraße 32 · 53842 Troisdorf · Germany | UST. ID Nr: DE154092803 (EU VAT ID) info@acsr.de | www.acsr.de | phone +49 2241 946994 · fax +49 2241 946996

Am 13.03.2015 um 16:07 schrieb Andreas Jung:
Warum verwendest Du nicht für jeden Prozess ein eigenes Filehandle?
Naja, das gleiche Fiel immer und immer wieder zu öffnen, Buffer dafür anzulegen, etc. scheint mir ineffizient. Aber wohl die einzige Lösung.

-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1
Hartmut Goebel wrote:
Am 13.03.2015 um 16:07 schrieb Andreas Jung:
Warum verwendest Du nicht für jeden Prozess ein eigenes Filehandle?
Naja, das gleiche Fiel immer und immer wieder zu öffnen, Buffer dafür anzulegen, etc. scheint mir ineffizient. Aber wohl die einzige Lösung.
Ein Haus baut man auch zuerst von unten nach oben anstatt mit dem Dach zu beginnen.
- -aj

Hartmut Goebel wrote:
Hallo,
ich habe ein kleine Nuss zu knacken:
Ich muss aus mehreren Prozessen aus dem gleichen File lesen. Das Problem ist, dass die gleichzeitigen Zugriffe und das nicht-atomare seek+read dazu führen, dass Schrott gelesen wird.
Dummerweise kann ich auch keine Funktionen aus dem Modul os verwenden, da es sich um einen Importer handelt – und os ist kein build-in Modul. damit kann ich also os.dup() ebenso wenig verwenden wie Semaphoren. Die Einzilge Lösung, die mit eingefallen ist, ist damit, das File bei jedem Lesezugriff neu zu öffnen.
Gibt es einen eleganteren /und effizienteren) Weg?
Hintergrund: Importer by PyInstaller: https://github.com/pyinstaller/pyinstaller/issues/1070
Unter Linux is os.dup eigentlich posix.dup und damit "eingebaut":
import os, sys os.dup.__module__
'posix'
os.dup.__module__ in sys.builtin_module_names
True
Wie das in Windows gehandhabt wird, musst du selber recherchieren -- ich vermute es ist genauso.

Am 13.03.2015 um 16:23 schrieb Peter Otten:
Wie das in Windows gehandhabt wird, musst du selber recherchieren -- ich vermute es ist genauso.
Wie das geht, steht oben im Modul `os`. Allerdings halte ich es nicht für sinnvoll, dieses Modul nach zu implementieren.

Am 13.03.2015 um 15:38 schrieb Hartmut Goebel:
Ich muss aus mehreren Prozessen aus dem gleichen File lesen. Das Problem ist, dass die gleichzeitigen Zugriffe und das nicht-atomare seek+read dazu führen, dass Schrott gelesen wird.
Hintergrund: Importer by PyInstaller: https://github.com/pyinstaller/pyinstaller/issues/1070
Ich habe das Gefühl, dass keiner der bisherigen Antwortenden das ticket gelesen hat.
Wenn ich es also richtig verstehe, verwendet der pyinstaller-Importer ein Filehandle auf das Zip-Archiv mit den zu importierenden Modulen, den er vom Parentprocess geerbt hat. Entweder muss also jeder Subprozess seinen eigen Filehandle öffnen oder du musst den Filepositionpointer durch ein Lock schützen.
Chris

Am 13.03.2015 um 16:53 schrieb Christopher Arndt:
oder du musst den Filepositionpointer durch ein Lock schützen.
Da müsste natürlich ein multiprocessing.Lock sein. Das Problem ist, wie übergibst du den Lock, da pyinstaller die Kindprozesse ja nicht selbst erzeugt.
Siehe zum Thema "interprocess locks" auch die interessanten Antworten hier:
http://stackoverflow.com/questions/6931342/system-wide-mutex-in-python-on-li...
Aber das scheint mir alles eher Herumdoktoren an den Symptomen als eine saubere Lösung zu sein. Entweder man muss damit leben, dass jeder Prozess das File selbst öffnet, oder man muss einen eigenen FileReader-Prozess implementieren, der z.B. über multiprocessing.Queues die Daten an Subprozesse weitergibt.
Chris

Am 13.03.2015 um 17:15 schrieb Christopher Arndt:
Da müsste natürlich ein multiprocessing.Lock sein. Das Problem ist, wie
Das Problem ist schon, dass ich in diesem Modul nur build-in Module verwenden kann und damit steht multiprocessing.Lock() nicht zur Verfügung.
Entweder man muss damit leben, dass jeder Prozess das File selbst öffnet, oder man muss einen eigenen FileReader-Prozess implementieren, der z.B. über multiprocessing.Queues die Daten an Subprozesse weitergibt.
Für eine ausgewachsene Multi-Porozess-Anwendung wäre ein Reader-Prozess wahrscheinlich einen gute Lösung. Aber nicht für ein Tool wie PyInstaller. Wir reden ja auch von der Laufzeit-Komponente. Und da ist es m.E. ziemlicher Overkill, *alle* Anwendungen zu Multi-Prozess-Anwendugen zu machen, nur um ein paar Sonderfälle abzudecken.

Hallo Christoher,
Am 13.03.2015 um 16:53 schrieb Christopher Arndt:
Ich habe das Gefühl, dass keiner der bisherigen Antwortenden das ticket gelesen hat.
Das Gefühl habe ich auch.
Wenn ich es also richtig verstehe, verwendet der pyinstaller-Importer ein Filehandle auf das Zip-Archiv mit den zu importierenden Modulen, den er vom Parentprocess geerbt hat.
Korrekt.
Entweder muss also jeder Subprozess seinen eigen Filehandle öffnen oder du musst den Filepositionpointer durch ein Lock schützen.
Schade. Ich hatte gehofft, er gibt einen "hack". Dann bleibt halt doch nur, das File jedes Mal neu zu öffnen.
participants (5)
-
Andreas Jung
-
Armin Stroß-Radschinski
-
Christopher Arndt
-
Hartmut Goebel
-
Peter Otten