Performance: 4x schnellere XSLT-Transformationen durch Worker-Pool

Problem: 82 XML-Dateien brauchten 160 Sekunden (JVM-Startup-Overhead)

Lösung: Persistente JVM-Worker-Prozesse mit JAXP Transformer API
- Saxon Worker Pool mit N persistenten JVM-Prozessen
- Eliminiert JVM-Startup und Classpath-Scanning bei jedem Job
- Parallele Verarbeitung mit ThreadPoolExecutor
- JAXP Transformer API (javax.xml.transform) - stabil, kein System.exit()
- Konfigurierbare Worker-Anzahl über Performance-Menü

Ergebnis: 82 Dateien in 40 Sekunden (4x Speedup, ~0.49s pro Datei)

Zusätzliche Verbesserungen:
- Dual-Logging (Datei + Konsole) mit Timestamps
- Worker-stderr-Logs in Projektverzeichnis/temp/
- Umfangreiche Debug-Ausgaben für Fehlerdiagnose
- Robuste Fehlerbehandlung mit ErrorListener

Technische Details:
- SaxonWorkerPool: Verwaltet N Worker-Prozesse
- JAXP statt Transform.main() (kein System.exit!)
- Worker-Locks für thread-sichere Job-Verteilung
- Graceful Shutdown mit EXIT-Befehl
- Fallback auf subprocess bei Pool-Fehlern

Dateien:
- src/saxon_pool.py (NEU): Worker-Pool-Implementation
- src/transform.py: Integration mit Worker-Pool
- src/ui/MainWindow.py: Pool-Initialisierung, Performance-Menü
- src/conf.py: max_workers Einstellung
- src/main.py: Dual-Logging

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
2025-12-28 16:46:39 +01:00
parent 055428e8cf
commit d0cdcd6432
5 changed files with 719 additions and 58 deletions
+9 -7
View File
@@ -62,8 +62,8 @@ class XslDir(BaseModel):
id: int
name: str
path_to_root_dir: Path
class SSLMode(str, Enum):
DISABLE = "disable"
ALLOW = "allow"
@@ -72,6 +72,7 @@ class SSLMode(str, Enum):
VERIFY_CA = "verify-ca"
VERIFY_FULL = "verify-full"
class PostgreSqlDb(BaseModel):
id: int
name: str
@@ -141,6 +142,7 @@ class AppSettings(BaseSettings):
pdf_projects: list[Project] = []
postgresql_dbs: list[PostgreSqlDb] = []
theme: str | None = None
max_workers: int = 8 # Anzahl paralleler Worker für Transformationen (Standard: 8)
# UI-Zustand
window_geometry: tuple[int, int, int, int] | None = None # (x, y, width, height)
@@ -165,7 +167,7 @@ class AppSettings(BaseSettings):
# Ordner existert nicht
if not config_path.parent.exists():
config_path.parent.mkdir(parents=True, exist_ok=True)
if not config_path.parent.is_dir() or not os.access(config_path.parent, os.W_OK):
logger.exception(f"{config_path.parent} ist kein Verzeichnis oder es gibt keine Schreibrechte")
sys.exit(1)
@@ -205,16 +207,16 @@ class ProjectData(BaseModel):
"""
nodes: list[TreeNode] = []
@classmethod
def readSettings(cls, project_dir: Path):
# Explizit UTF-8 Encoding verwenden
project_yaml_path = project_dir / "project.yaml"
with open(project_yaml_path, 'r', encoding='utf-8') as f:
yaml = YAML(typ='safe')
with open(project_yaml_path, "r", encoding="utf-8") as f:
yaml = YAML(typ="safe")
yaml_data = yaml.load(f)
return cls.model_validate(yaml_data)
def writeSettings(self, project_dir: Path):
with open(project_dir / "project.yaml", "w", encoding="utf8") as f:
f.write(to_yaml_str(self))