Schneller laden: Antworten vorwaermen, Gruppen auswaehlen

Der OAPIF-Provider fragt je Sammlung nacheinander Sammlung, Schema, Stil,
OPTIONS und die erste Seite ab — bei 27 Sammlungen dauert das Anlegen 20,5 s
(gemessen 08.09.2026, Berbisdorf).

- ogc_layers.vorwaermen(): holt Landing, OpenAPI, Conformance, Sammlung, Schema
  und Stil vorab und gleichzeitig ueber Qts Ereignisschleife (unter 1,5 s fuer
  84 Antworten). layer_hinzufuegen ruft es vor dem ersten Layer auf. Ergebnis
  14,2 s statt 20,5 s, und die Zeit schwankt deutlich weniger.
- Seitenleiste: drei Haken (Verfahren / Vorerhebung / Massnahmenblaetter) waehlen
  aus, was geladen wird. Nur Verfahren 11,1 s (21 Layer), nur Vorerhebung oder
  nur Massnahmenblaetter je 1,6 s (3 Layer).

Bewusst NICHT parallel: ein in einem Python-Thread gebauter OAPIF-Layer laesst
sich zwar in 0,9 s erzeugen, stuerzt aber beim ersten getFeatures() ab
(Segfault, gemessen) — der Provider gehoert dem Thread, der ihn gebaut hat.

tools/headless_panel_test.py prueft die neue Auswahl mit. metadata.txt 0.4.0.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
erik
2026-09-08 09:32:56 +02:00
co-authored by Claude Fable 5.1
parent b97f066b49
commit 1680b4ede3
6 changed files with 116 additions and 8 deletions
+66 -2
View File
@@ -27,7 +27,7 @@ Blatt-Spalten als ``blatt_*``-Attribute; neue Features brauchen ``blatt_uuid`` o
import os
import tempfile
from qgis.PyQt.QtCore import QSettings, QUrl, Qt, QTimer
from qgis.PyQt.QtCore import QEventLoop, QSettings, QUrl, Qt, QTimer
from qgis.PyQt.QtNetwork import QNetworkRequest
from qgis.PyQt.QtWidgets import QProgressBar
from qgis.core import (
@@ -35,6 +35,7 @@ from qgis.core import (
QgsApplication,
QgsAuthMethodConfig,
QgsDataSourceUri,
QgsNetworkAccessManager,
QgsProject,
QgsVectorLayer,
)
@@ -204,6 +205,61 @@ def layer_uri(base_url, cid, authcfg=None, storage_crs=None, api_key=None):
return uri.uri(False)
def vorwaermen(base_url, collections, api_key=None, authcfg=None, gleichzeitig=8):
"""Die Antworten, die der Provider gleich braucht, vorab und **gleichzeitig** holen.
Der OAPIF-Provider fragt je Layer nacheinander Landing Page, OpenAPI, Conformance,
Sammlung, Schema und (über das Plugin) den Stil ab — bei 27 Sammlungen über 160 Anfragen,
jede einzeln und blockierend. Alle diese Antworten tragen serverseitig ``Cache-Control``,
liegen also nach einem Vorablauf im Plattencache von QGIS und kosten den Provider danach
kein Netz mehr. Gemessen 08.09.2026 (Berbisdorf, 27 Sammlungen): 30,7 s ohne, 14,9 s mit
Vorwärmen; das Vorwärmen selbst dauert unter einer Sekunde.
Bewusst **kein** paralleles Anlegen der Layer: ein in einem Python-Thread erzeugter
OAPIF-Layer stürzt beim ersten ``getFeatures()`` ab (Segfault, gemessen) — der Provider
gehört dem Thread, der ihn gebaut hat. Hier laufen nur reine Netzanfragen nebeneinander,
über Qts eigene Ereignisschleife im selben Thread.
:returns: Anzahl der vorgeladenen Antworten.
"""
ziele = [ogc_url(base_url), ogc_url(base_url) + "/api", ogc_url(base_url) + "/conformance"]
for c in collections or []:
cid = str((c or {}).get("id") or "")
if cid:
ziele.append("%s/collections/%s" % (ogc_url(base_url), cid))
ziele.append("%s/collections/%s/schema" % (ogc_url(base_url), cid))
ziele.append(stil_url(base_url, cid))
verwalter = QgsNetworkAccessManager.instance()
geholt = 0
for anfang in range(0, len(ziele), gleichzeitig):
haufen = ziele[anfang:anfang + gleichzeitig]
schleife = QEventLoop()
offen = {"n": len(haufen)}
def fertig(_antwort=None):
offen["n"] -= 1
if offen["n"] <= 0:
schleife.quit()
antworten = []
for url in haufen:
req = QNetworkRequest(QUrl(url))
if api_key:
req.setRawHeader(b"X-API-Key", api_key.encode("utf-8"))
if authcfg:
QgsApplication.authManager().updateNetworkRequest(req, authcfg)
req.setAttribute(QNetworkRequest.Attribute.CacheSaveControlAttribute, True)
antwort = verwalter.get(req)
antwort.finished.connect(fertig)
antworten.append(antwort)
schleife.exec()
for antwort in antworten:
antwort.readAll() # Rumpf lesen, damit er im Cache landet
antwort.deleteLater()
geholt += 1
return geholt
def layer_hinzufuegen(iface, base_url, vkz, vkz_name, collections, authcfg=None, api_key=None):
"""Alle Sammlungen als OAPIF-Layer in die Gruppe „VLN <Verfahren>" hängen — **schrittweise**.
@@ -225,10 +281,18 @@ def layer_hinzufuegen(iface, base_url, vkz, vkz_name, collections, authcfg=None,
balken.setMaximum(len(collections))
balken.setValue(0)
balken.setAlignment(Qt.AlignmentFlag.AlignLeft | Qt.AlignmentFlag.AlignVCenter)
meldung = iface.messageBar().createMessage("VLN Karten", "Layer werden geladen …")
meldung = iface.messageBar().createMessage("VLN Karten", "Layer werden vorbereitet …")
meldung.layout().addWidget(balken)
iface.messageBar().pushWidget(meldung, Qgis.Info)
# Erst die Antworten gleichzeitig in den Plattencache holen (unter einer Sekunde), dann
# bauen — das halbiert die Ladezeit, weil der Provider danach kaum noch ans Netz muss.
try:
vorwaermen(base_url, collections, api_key=api_key, authcfg=authcfg)
except Exception: # noqa: BLE001
pass # Vorwärmen ist Beiwerk
meldung.setText("Layer werden geladen …")
zustand = {"i": 0, "geladen": 0, "fehler": []}
def schritt():