Performance-Revolution: Saxon-Worker-Pool eliminiert JVM-Startup-Overhead
Implementiert persistente JVM-Worker-Pool für 5-10x schnellere Transformationen: VORHER: - 82 Dateien in 60s (12 Worker) = 0.73s/Datei - JVM-Start bei jeder Transformation (~500ms Overhead) - Classpath wird jedes Mal neu geladen NACHHER (erwartet): - 82 Dateien in ~8-12s (12 Worker) = 0.10-0.15s/Datei - JVM läuft persistent (einmalig ~500ms beim Start) - 5-10x schneller! 🚀 Architektur: - SaxonWorkerPool: Verwaltet N lang-laufende JVM-Prozesse - SaxonWorker.java: Java-Daemon der Saxon-Transformationen ausführt - Kommunikation via stdin/stdout (Tab-separated Job-Format) - Automatisches Fallback auf subprocess bei Pool-Fehlern - Graceful Shutdown beim Beenden der Anwendung Neue Dateien: - src/saxon_pool.py: Worker-Pool-Implementierung - Kompiliert SaxonWorker.java zur Laufzeit - Startet N JVM-Prozesse beim Projekt-Öffnen - Thread-safe Job-Verteilung mit Locks - Context Manager für sauberen Shutdown Änderungen: - transform.py: Nutzt Pool wenn verfügbar, Fallback auf subprocess - MainWindow.py: Initialisiert Pool beim Projekt-Öffnen, beendet bei Close - set_saxon_worker_pool() zum globalen Pool-Management Technische Details: - Java-Code als String eingebettet, Runtime-Kompilierung mit javac - stdout für Job-Ergebnisse, stderr für Saxon-Logs - Tab-separated Format: source\txsl\toutput\tparams - Worker antworten mit "OK" oder "ERROR: message" Nächster Test wird zeigen ob 8-12s erreicht werden! 🎯 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
+44
-5
@@ -11,10 +11,26 @@ import logging
|
||||
import subprocess
|
||||
from pathlib import Path
|
||||
from datetime import datetime
|
||||
from typing import Any
|
||||
from typing import Any, Optional, TYPE_CHECKING
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from saxon_pool import SaxonWorkerPool
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
# Globaler Saxon-Worker-Pool (wird von MainWindow initialisiert)
|
||||
_saxon_worker_pool: Optional["SaxonWorkerPool"] = None
|
||||
|
||||
|
||||
def set_saxon_worker_pool(pool: Optional["SaxonWorkerPool"]):
|
||||
"""Setzt den globalen Saxon-Worker-Pool."""
|
||||
global _saxon_worker_pool
|
||||
_saxon_worker_pool = pool
|
||||
if pool:
|
||||
logger.info(f"Saxon-Worker-Pool aktiviert mit {pool.num_workers} Workern")
|
||||
else:
|
||||
logger.info("Saxon-Worker-Pool deaktiviert (Fallback auf subprocess)")
|
||||
|
||||
|
||||
class TransformationJob:
|
||||
"""
|
||||
@@ -164,6 +180,31 @@ class TransformationJob:
|
||||
logger.error(error_msg)
|
||||
return False, error_msg
|
||||
|
||||
logger.info(f"Starte Saxon-Transformation: {self.xml_file.name}")
|
||||
|
||||
# Versuche zuerst den Worker-Pool zu nutzen (schneller!)
|
||||
global _saxon_worker_pool
|
||||
if _saxon_worker_pool:
|
||||
try:
|
||||
success, message = _saxon_worker_pool.transform(
|
||||
source_xml=xml_abs,
|
||||
xsl_stylesheet=self.xsl_file,
|
||||
output_fo=self.temp_fo,
|
||||
xslt_params=self.xslt_params,
|
||||
)
|
||||
|
||||
if success:
|
||||
logger.info(f"Saxon-Transformation erfolgreich (Worker-Pool): {self.xml_file.name}")
|
||||
else:
|
||||
logger.error(f"Saxon-Transformation fehlgeschlagen (Worker-Pool): {message}")
|
||||
|
||||
return success, message
|
||||
|
||||
except Exception as e:
|
||||
logger.warning(f"Worker-Pool-Fehler, Fallback auf subprocess: {e}")
|
||||
# Fallback auf subprocess unten
|
||||
|
||||
# Fallback: Traditionelle subprocess-Methode (langsamer, aber robuster)
|
||||
# XSLT-Parameter formatieren
|
||||
params = [f"{key}={value}" for key, value in self.xslt_params.items()]
|
||||
|
||||
@@ -196,7 +237,6 @@ class TransformationJob:
|
||||
logger.debug("Classpath aus Cache verwendet")
|
||||
|
||||
# Saxon-Kommandozeile
|
||||
# Verwende -cp mit allen JARs und rufe Transform-Main direkt auf
|
||||
cmd_line = [
|
||||
str(self.java_vm_path),
|
||||
"-cp",
|
||||
@@ -208,8 +248,7 @@ class TransformationJob:
|
||||
*params,
|
||||
]
|
||||
|
||||
logger.info(f"Starte Saxon-Transformation: {self.xml_file.name}")
|
||||
logger.debug(f"Kommandozeile: {' '.join(cmd_line)}")
|
||||
logger.debug(f"Kommandozeile (subprocess fallback): {' '.join(cmd_line)}")
|
||||
|
||||
try:
|
||||
result = subprocess.run(
|
||||
@@ -226,7 +265,7 @@ class TransformationJob:
|
||||
logger.debug(f"Saxon StdErr:\n{result.stderr}")
|
||||
|
||||
if result.returncode == 0:
|
||||
logger.info(f"Saxon-Transformation erfolgreich: {self.xml_file.name}")
|
||||
logger.info(f"Saxon-Transformation erfolgreich (subprocess): {self.xml_file.name}")
|
||||
return True, "Erfolgreich"
|
||||
else:
|
||||
error_msg = (
|
||||
|
||||
Reference in New Issue
Block a user