Sqlite Multithread Zugriff? Alternativen?

Installation und Anwendung von Datenbankschnittstellen wie SQLite, PostgreSQL, MariaDB/MySQL, der DB-API 2.0 und sonstigen Datenbanksystemen.
Antworten
m.g.o.d
User
Beiträge: 75
Registriert: Samstag 4. April 2020, 13:17

Hallo Zusammen,

bisher habe ich mich nur mit SQLite Datenbanken beschäftigt und kenne mich mit den anderen Varianten noch nicht aus.

Folgende Frage hätte ich, wo Sqlite wahrscheinlich an seine Grenzen kommt:

Ich habe x-Threads parallel gestartet (z.B: 5). Diese sollen np.arrays (nach entsprechender Konvertierung) zu unterschiedlichen Zeiten in eine Datenbank schreiben und lesen können. Es wäre auch möglich (wenn auch unwahrscheinlich), dass zwei Threads zur gleichen Zeit unterschiedliche Arrays einlesen oder schreiben wollen.

Nun habe ich gelesen, dass diese Operation von SQLite für mehr als ein Thread nicht erlaubt ist? Es gibt da wohl dieses "Write-Ahead Log", was nach meinem Verständnis verschiedene Schreibvorgänge puffert und der Reihe nach abarbeitet...aber wohl auch nur für maximal einen Thread.:
https://www.skoumal.com/en/parallel-rea ... in-sqlite/

Könntet ihr mir Tips geben, wie ich diese Anforderung mit Datenbanken in Python realisieren könnte?

Eine leichtere Lösung wäre, eine Ordnerstruktur anzulegen und die Arrays (es sind openCV frames) als jpegs zu speichern und dann einzulesen. Aber eine Datenbank wäre mir schon lieber.

Ich würde mich über ein paar Hinweise sehr freuen.

Besten Gruß,
Marc
__deets__
User
Beiträge: 14493
Registriert: Mittwoch 14. Oktober 2015, 14:29

Python ist bedingt durch das GIL nicht besonders gut im echten parallelen abarbeiten von Threads. Gegebenenfalls solltest du also auf multiprocessing ausweichen.

Und zu deinem Problem: du kannst zB einfach einen dezidierten Writer-Thread (oder eben Prozess) machen, und dem Arbeitsauftraege per Queue reinreichen.
Benutzeravatar
noisefloor
User
Beiträge: 3843
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

Hallo,

SQLite ist threadsafe, wenn es entsprechend kompiliert ist. Ist das SQLite, was Python an Board hat, normalerweise. Kannst du über `pragma COMPILE_OPTIONS` abfragen. Wenn bei `THREADSAFE` eine 1 oder 2 steht, ist es threadsafe.

Was aber nicht daran ändert, dass nur ein Schreibvorgang gleichzeitig geht, dass ist eine generelle Eigenschaft von SQLite. Wenn SQLite threadsafe kompiliert ist heißt das nur, dass Multithreading nicht zu Problemen führen sollte. Paralleles Schreiben geht dann trotzdem nicht.

Gruß, noisefloor
m.g.o.d
User
Beiträge: 75
Registriert: Samstag 4. April 2020, 13:17

Hallo und danke euch für eure Kommentrare

@__deets__ gibt es in dieser Architektur das Problem mit Gil auch? Ich nutze zwar QRunnable und QThread, aber das ändert wohl nichts am Interpreter, oder? Ich müsste also die QRunnable Klasse, welche zwei QThreads starten soll, durch eine entsprechende Implementierung von multiprocessing ersetzten, korrekt? Das heisst, mutliprocessing startet z.B. 5 Hauptprozesse, die dann wiederrum jeweils 2 QThreads starten? ODer darf ich QThread dann gar nicht mehr verwenden?! Allerdings habe ich auch Daten, die ich an die GUI weiterreichen muss und das kann ich durch die Signale halt gut machen...bei multiprocessing fange ich wieder bei 0 an.

Ok und zur der Queue, also dein Vorschlag würde also die Schreib- und Lesevorgänge puffern, um ein sequentielles Abarbeiten zu erreichen und zu verhindert, dass etwas parallel an die SQLite angefragt wird, richtig?

So mache ich es aktuell:

Code: Alles auswählen

        
# Starting Core Thread
for _ in range(len(channelnames_ok)):
     self.threadpool.setMaxThreadCount(len(channelnames_ok))         # Set Threadnumber acording to database entries 
     worker = GraphicAlarmMachine(channelnames_ok[_])                # parse channelname and PTS parameters to each seperate thread
     self.threadpool.start(worker)  



class GraphicAlarmMachine(QRunnable):
    """ start two child threads for parent thread """
 
    def __init__(self, channel):
        super().__init__()
        self.channel = channel
        self.signals = WorkerSignalHolder()
        self.thread_create()

    def thread_create(self):
        self.cornerbug_thread = QThread() 
        self.cornerbug_init = CornerbugCheck(self.channel)
        self.cornerbug_init.moveToThread(self.cornerbug_thread)
        self.cornerbug_init.start()

        self.design_thread = QThread() 
        self.design_init = DesignCheck(self.channel)
        self.design_init.moveToThread(self.design_thread)
        self.design_init.start()


 def run(self):
        pass
__deets__
User
Beiträge: 14493
Registriert: Mittwoch 14. Oktober 2015, 14:29

QThread ändert das Python threading Modell nicht.

Wenn die Threads IO-Bound sind, ist multiprocessing wohl nicht notwendig. Es stellt sich dann aber auch die Frage, warum es überhaupt mehr als zwei Threads sind. Wenn die eh nur warten, reicht auch ein extra Thread mit Arbeitsaufträgen. Und der GUI thread.

Und parallel in die DB schreibt dann auch keiner. Wobei das laut noise floor ja wohl geht, aber dann eh serialisiert wird.
m.g.o.d
User
Beiträge: 75
Registriert: Samstag 4. April 2020, 13:17

__deets__ hat geschrieben: Samstag 30. Januar 2021, 18:06 QThread ändert das Python threading Modell nicht.

Wenn die Threads IO-Bound sind, ist multiprocessing wohl nicht notwendig. Es stellt sich dann aber auch die Frage, warum es überhaupt mehr als zwei Threads sind. Wenn die eh nur warten, reicht auch ein extra Thread mit Arbeitsaufträgen. Und der GUI thread.

Und parallel in die DB schreibt dann auch keiner. Wobei das laut noise floor ja wohl geht, aber dann eh serialisiert wird.
Ja ich bin auch gerade am überlegen, ob es nicht eigentlich IO-Bounds sind...der Grund, warum ich zwei Threads machen wollte, war, dass es möglich ist, dass zwei parallele Schreib- oder Lesevorgänge passieren können.

Ich muss kurz skizzieren, um was es geht, damit vielleicht mein Problem besser verstanden wird:

Ich habe Zugriff auf einen Videoserver, der regelmäßig mp4 Videos von vielen unterschiedlichen Quellen schreibt. Nun möchte ich jede dieser Quellen untersuchen, ob grafische Insertierungen (Logos und sonstige Effekte) auch wirklich im Video gefunden werden oder nicht. Nun kann aber z.B. ein Effekt auch zeitgleich mit einem Logo auftreten (deshalb parallele Threads). Ich habe eine Liste, die alle Einblendzeiten dieser Effekte beeinhaltet. Ich lege den Thread also schlafen, bis die Zeit der EInblendung erreicht ist. Der Thread arbeitet dann für die Dauer des Effekts und schläft anschließend wieder bis zur nächsten EInblendung.

Es gibt pro Quelle einen Thread für die Logos (mit der Liste mit den entsprechenden Einblendezeiten) und einen Thread für die sonstigen Grafiken (inkls. entsprechender Liste für die Einblendezeiten der Grafiken).

Das heisst, ich möchte z.B. 10 Quellen untersuchen, dann habe ich 20 Threads, die mal schlafen, mal arbeiten (je nach den zugrunde liegenden Zeiten). Also 10 Threads für die Logos und 10 Threads für die Grafiken mit unterschiedlichen Daten.

Für die Untersuchung habe ich dann die Effekte oder Grafikdateien im Video als np.array extrahiert und kann die mittels openCV TM_SQDIFF = Minimum Square Difference with Threshold mit den vorliegenden Videos untersuchen (Danke @__deets__ auch für den Hinweis bei cv2!)

Die np.array wollte ich eben in die Datenbank schreiben, was aber dann nicht mit SQLite nicht funktionieren dürfte, oder zumindest nur mit wenigen Threads.
__deets__
User
Beiträge: 14493
Registriert: Mittwoch 14. Oktober 2015, 14:29

Da Python eh nicht parallel abarbeitet, wuerde ich deine Aufteilung in Threads in Frage stellen. Also, GUI-Thread und Worker Thread bleibt natuerlich bestehen, sonst hakelt die GUI.

Aber basierend auf einem Frame kannst du du doch in einem Thread die diversen Tests nacheinander fahren. Faktisch passiert das schon jetzt, denn dank dem GIL kann dein Programm eh nicht zeitgleich arbeiten. Du hast es nur komplizierter implementiert, statt einfach in einer for-Schleife durch eine Reihe von Tests zu laufen, und deren Ergebnisse zu berechnen.
m.g.o.d
User
Beiträge: 75
Registriert: Samstag 4. April 2020, 13:17

__deets__ hat geschrieben: Samstag 30. Januar 2021, 19:12 Da Python eh nicht parallel abarbeitet, wuerde ich deine Aufteilung in Threads in Frage stellen. Also, GUI-Thread und Worker Thread bleibt natuerlich bestehen, sonst hakelt die GUI.

Aber basierend auf einem Frame kannst du du doch in einem Thread die diversen Tests nacheinander fahren. Faktisch passiert das schon jetzt, denn dank dem GIL kann dein Programm eh nicht zeitgleich arbeiten. Du hast es nur komplizierter implementiert, statt einfach in einer for-Schleife durch eine Reihe von Tests zu laufen, und deren Ergebnisse zu berechnen.
Mhh dann weiss ich aber nicht, wie ich das in Python machen kann. Denn klar kann ich eine große Liste bauen und alle Daten samt Startzeit da hinein packen. Aber wenn nun ein Test 20 Minuten dauert (weil z.B. das Logo 20 Minuten im Video ist) und ein anderer Test 40 Sekunden dauert, diese Zeit aber innerhalb der Logozeit liegt, dann muss ich meinen Test des Logos ja unterbrechen und anschließend fortführen? Ich wüsste nicht, wie ich so eine Queue-Liste bauen könnte, die sinnvoll sequentiell abgearbeitet werden kann. Wenn sich Eventzeiten überlappen, würden Events so auch unter Umständen übersprungen...ich muss darüber nachdenken. Dann könnte ich wenigstens SQLite verwenden. Danke jedenfalls für alle Hinweise bis hierher.
__deets__
User
Beiträge: 14493
Registriert: Mittwoch 14. Oktober 2015, 14:29

Vielleicht solltest du noch ein bisschen weiter ausholen, was du da machst. Aber selbst mit dieser Information: jeder Test kann doch zwangsweise immer nur pro Frame stattfinden. Der 1000ste Frame hat einen Zeitstempel, und wenn du da vorher festgelegt hast, was dann geprüft werden soll, dann prüfst du eben 1, 2 oder 3 Dinge pro Frame.

So wie du das beschreibst macht ein thread einfach nach 20 Minuten innehalten etwas für eine gewisse Zeit. Und da hast du dann noch 3 andere. Aber faktisch können die doch trotzdem nur jeweils auf dem gleich Frame rumrödeln.

Alles unter der Annahme wir reden über einen Quellstrom. Wenn du mehrere Videos bearbeiten willst, DANN lohnt sich natürlich nebenläufigkeit. Aber echte. Also multiprocessing.
Benutzeravatar
noisefloor
User
Beiträge: 3843
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

Hallo,

@m.g.o.d.: Bezieht sich das "bestimmte Zeit" aus dem Ausgangspost auf den tatsächlichen Zeitstempel, wo der Thread etwas "findet" oder auf den Zeitpunkt im Video, also so was wie "nach 3 Minuten 25 Sekunden Abspielzeit des Videos"?

Gruß, noisefloor
Antworten