Einzelnen Beitrag anzeigen

Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.184 Beiträge
 
Delphi 12 Athens
 
#15

AW: Wie Embedded-Python und PIP?

  Alt 11. Jan 2024, 17:55
Nja, wir hatten ursprünglich Python als "Embedded" mitgeliefert (nur nannte es damals noch niemand so).
Also als ZIP runtergeladen und die EXE (inkl. DLL und Co.) als Unterverzeichnis beim Programm.

Das aktuelle Script wurde als .py-Datei auf die Festplatte geschieben,
dann die Python.exe gestartet, die Datei als Parameter übergeben und dann via ShellExecute/CreateProzess die Ausgabe in eine Datei umgeleitet.
Später der Ausgabestream direkt im CreateProzess übergeben und die Ausgabe in ein unsichtbares TMemo, was dann weiterverwendet wurde und sich beim Dedbuggen anzeigen ließ.

Zuletzt dann Python4Delphi eingeführt, wo das Script als Stream/String im Programm bleibt und auch die Ausgabe in einem Stream/String landet.
Zusätzlich noch ein paar Variablen und Delphi-Funktionen reingegeben, welche sich im Python nutzen lassen.
Auch lässt sich hier intern schöner die Fehlerbehandlung machen. Also vorher ein SyntaxCheck und bei einem Fehler erweiterte Fehlerinfos von der DLL abrufen.

Dann ging es darum auch Fremdcode zu nutzen (bisher vorwiegend nur selbsterstellte PythonScripte)
und da sind wir dann zu PIP übergegangen, da es manuell schnell umständlich wird, mit all den Abhängigkeiten.

Als allerletztes dann noch die Ausgabe im Python auf Unicode umgestellt, denn rein ging es schon als Unicode, aber die Ausgabe sollte eigentlich UTF-8 sein (war aber ANSI).



Bei der EXE war es so, dass die Python-Instanz immer neu ist
und ein Script niemals Auswirkungen auf nachfolgende Scripte hat.

-> Wurde z.B. in einem Script vergessen eine Variable zu initialisieren,
dann was diese Variable in der EXE immer leer,
aber nun in der DLL hatte sie den Wert einer vorhergehenden Ausführung, was das Verhalten manchmal plötzlich veränderte.



Da wir damals es nicht geschafft hatten, die Instanz (Variablen und geladene Module) zurückzusetzen,
wird aktuell nach jeder Ausführung eines Scriptes die Instanz freigegeben und die Python-DLL entladen.
Beim nächsten Laden war somit alles wieder neu/leer.
Das lief bisher gut und auch flott.

Dann versuchte jemand PySide2 und shiboken2 nutzen zu wollen.
Ersteres lädt selbst DLLs und entlädt sich nicht mehr. (Entwickler für Scriptsprachen sind einfach nur faule Schlampen ... siehe meine Signaur)

Diese DLLs haben auch noch eine Referenz auf die python3.dll, welche wiederrum die python38.dll (welche wir geladen haben und nutzen) referenziert, womit sich alles gegenseitig im RAM festkrallt, nachdem wir unsere Referenz auf die python38.dll freigaben und dachten es wäre nun entladen.

Erstmal hatte hier Python4Delphi einen Bug, so dass es in der Finalisazion beim Entladen der einen DLL einen Exception gibt (das ist OK), aber nachfolgend anderes vergessen wird zu finalisieren und freizugeben. (try-finally vergessen)

Dennoch bleibt irgendwas im RAM (auch wenn manuell alle DLLs entladen werden), was dann beim nächsten Laden und der Initialisation zu einer Exception führt und es nicht mehr erlaubt weitere Scripte auszuführen (python4delphi bricht beim Laden und starten des Scripts ab).

Ja, ich kann manuell diese DLLs in der richigen Reihenfolge entladen (testweise für PySide2 gemacht),
aber da der Code universell sein muß, weil ich garnicht weiß, welche Komponenten/PythonModule zukünftig genuzt werden.
Hier hab ich mich nun mühevoll in Windows "gehackt", um an die LadeListen der DLLs zu kommen (inkl. Rehenfolge/Uhrzeit und dem Grund des Ladens, also manuell oder durch automatische Abhängigkeit)
Das wird nun genutzt die FremdDLLs zu finden und zu entladen.

Aber wie gesagt, irgendwo bleibt noch was zurück und knallt nachfolgend. Das hatte ich noch nicht gefunden, drum hängt das Projekt hier erstmal, da Anderes wichtiger.
$2B or not $2B

Geändert von himitsu (11. Jan 2024 um 18:07 Uhr)
  Mit Zitat antworten Zitat