Connect with us

Entwicklung & Code

Software Testing: Wenn GenAI gegen ethische Werte von Menschen verstößt


Generative KI einfach nicht zu nutzen, weil sie den eigenen Werten widerspricht: Das ist die Position, die Johannes Link konsequent vertritt. Richard Seidl spricht mit ihm darüber, warum er hyperskalierte GenAI für ethisch nicht vertretbar hält und was ihn zu diesem Schluss gebracht hat. Die beiden reden über Trainingsdaten, die ohne Zustimmung der Urheber verwendet werden, über den massiven Energieverbrauch, über den Zerfall des freien Internets und darüber, was mit Studierenden passiert, die das Schreiben und Denken delegieren, bevor sie es je wirklich geübt haben. Johannes Link erklärt auch, was sich ändern müsste, damit er seine Meinung überdenken würde, und ob er diesen Wandel für realistisch hält.

Weiterlesen nach der Anzeige


Richard Seidl

Richard Seidl

Richard Seidl ist Berater, Speaker und Podcast-Host. Für ihn ist klar: Wer heute exzellente Software kreieren möchte, denkt den Entwicklungsprozess ganzheitlich: Menschen, Kontext, Methoden und Tools. Er hat seine Erfahrungen in acht Fachbüchern veröffentlicht, betreibt erfolgreich zwei Community-Podcasts und ist Beirat der heise-Konferenz betterCode() Testing.

„Ein statistisches Modell kennt weder richtig noch falsch, noch Wahrheit.“ – Johannes Link

Johannes Link programmiert seit mehr als 40 Jahren, 30 davon im Beruf. Seit Ende des letzten Jahrhunderts stehen Extreme Programming und andere auf den Menschen ausgerichtete Softwareentwicklungsansätze im Zentrum seiner Tätigkeit. Im beruflichen Fokus steht die (Um-)Gestaltung von Teams hin zu mehr Eigenverantwortung und Selbststeuerung. Die sinnvolle und ethische Gestaltung seines privaten und beruflichen Lebens treibt ihn seit Jahren um. Mit dem Thema GenAI beschäftigt er sich seit den frühen Tagen von OpenAIs GPT-Sprachmodellen.

Dieses Format fokussiert sich auf Softwarequalität: Ob Testautomatisierung, Qualität in agilen Projekten, Testdaten oder Testteams – Richard Seidl und seine Gäste betrachten die Dinge, die die Qualität in der Softwareentwicklung steigern.

Die aktuelle Episode ist auch auf Richard Seidls Blog verfügbar.

Weiterlesen nach der Anzeige


(mai)



Source link

Entwicklung & Code

OpenCV 5.0 bringt LLMs in die Computer-Vision-Bibliothek


Mit OpenCV 5.0 ist eine neue Hauptversion der weit verbreiteten Computer-Vision-Bibliothek erschienen. Kern des Releases ist eine komplett neu entwickelte Deep-Learning-Engine (DNN). Sie unterstützt deutlich mehr ONNX-Modelle als bisher, führt moderne Transformer-Architekturen effizienter aus und verarbeitet erstmals auch Sprachmodelle (LLMs) und Vision-Language-Modelle (VLMs) direkt in OpenCV. Außerdem modernisieren die Entwickler den Kern der Bibliothek, bauen die Hardwarebeschleunigung aus und erweitern die 3D-Funktionen.

Weiterlesen nach der Anzeige

OpenCV (Open Source Computer Vision Library) zählt zu den wichtigsten Open-Source-Bibliotheken für die Bildverarbeitung und Computer Vision. Sie kommt unter anderem in der Robotik, der Industrieautomation, der Medizintechnik, in AR/VR-Anwendungen und in Embedded-Systemen zum Einsatz. Die Bibliothek bietet zahlreiche Algorithmen für Bilderkennung, Objekterkennung, Kalibrierung, Tracking und 3D-Rekonstruktion.

Die wichtigste Neuerung ist die überarbeitete DNN-Engine. Nach Angaben des Projekts steigt die Unterstützung für ONNX-Operatoren von rund 22 Prozent in der 4.x-Reihe auf über 80 Prozent. ONNX (Open Neural Network Exchange) hat sich als verbreitetes Austauschformat für KI-Modelle etabliert. Bisher scheiterte der Import moderner Modelle in OpenCV oft an fehlenden Operatoren oder an Einschränkungen bei dynamischen Eingabegrößen.

Die neue Engine setzt auf eine graphbasierte Ausführung: Sie verarbeitet Modelle nicht mehr als einfache Folge von Schichten, sondern analysiert sie als Berechnungsgraph. Das erlaubt Optimierungen wie Shape Inference, Constant Folding und Operator Fusion. Neu sind außerdem die Unterstützung dynamischer Shapes, von Kontrollfluss-Konstrukten wie If– und Loop-Blöcken sowie von Quantisierungsgraphen.

Für aktuelle KI-Modelle besonders relevant ist die Attention Fusion: Die Engine erkennt typische Transformer-Muster und fasst mehrere Operationen zu einer einzigen, optimierten Berechnung zusammen. Das soll moderne Transformer-Modelle beschleunigen und den Speicherbedarf senken. Details zur neuen Engine beschreibt das Projekt im Überblick zu OpenCV 5 auf der Projektseite.

Hinzu kommt die Integration von Sprach- und multimodalen Modellen. Dafür bringt OpenCV 5 einen eigenen Tokenizer und einen KV-Cache für die autoregressive Textgenerierung mit. Unterstützt werden unter anderem die Modellfamilien Qwen 2.5, Gemma 3 und PaliGemma (partiell). So deckt OpenCV nicht mehr nur klassische Bildverarbeitung ab, sondern auch Vision-Language-Szenarien – etwa, wenn ein Modell ein Bild analysiert und anschließend in natürlicher Sprache beschreibt.

Weiterlesen nach der Anzeige

Um die Umstellung bestehender Anwendungen zu erleichtern, bleibt die bisherige DNN-Engine erhalten. OpenCV 5 stellt damit drei Ausführungsvarianten bereit: die neue Engine, die klassische Engine und optional ONNX Runtime. Anwendungen können je nach Bedarf zwischen den Varianten wechseln, ohne ihre DNN-API anzupassen. Welche Engine zum Einsatz kommt, lässt sich beim Laden eines Modells über einen Parameter aus dem Enum cv::dnn::EngineType steuern; standardmäßig wählt ENGINE_AUTO automatisch die passende Variante.

Auch beim Feature-Matching setzt OpenCV stärker auf Deep Learning. Das neue Modul Features löst das bisherige Features2D ab und ergänzt klassische Verfahren wie SIFT oder ORB um neuronale Alternativen, darunter ALIKED, DISK und LightGlueMatcher. Solche Verfahren kommen etwa beim Zusammensetzen von Panoramen, bei Visual SLAM oder bei 3D-Rekonstruktionen zum Einsatz.

LightGlue nutzt Attention-Mechanismen, um Bildmerkmale robuster zuzuordnen als klassische Verfahren. Die klassischen Detektoren bleiben dabei erhalten, sodass sich der neue Deep-Learning-Pfad und die etablierten Methoden je nach Anwendungsfall kombinieren lassen.

Modernisiert haben die Entwickler auch den Kern der Bibliothek. OpenCV unterstützt nun die Datentypen FP16 und BF16, die in aktuellen KI-Beschleunigern weit verbreitet sind, dazu Bool und weitere Integer-Varianten. Die Matrixklasse cv::Mat kann erstmals echte 0D- und 1D-Strukturen abbilden und beherrscht jetzt Broadcasting sowie weitere N-dimensionale Operationen. Das soll viele Umwege und Konvertierungen ersparen.

Bei den Schnittstellen trennt sich das Projekt schrittweise von Altlasten: Die historische C-API gilt nun offiziell als veraltet. Für Python unterstützt OpenCV 5 NumPy 2.x und integriert benannte Parameter stärker, sodass sich Funktionen lesbarer aufrufen lassen – etwa cv.someAlgorithm(threshold=0.5) statt einer rein positionsbasierten Übergabe.

Ein weiteres zentrales Thema ist die Hardwarebeschleunigung. Die Entwickler haben die Hardware Abstraction Layer (HAL) grundlegend überarbeitet, um optimierte Implementierungen verschiedener Hardwarehersteller leichter einzubinden. Das Projekt nennt unter anderem Intel IPP, Arm KleidiCV, Qualcomm FastCV und die Unterstützung der Vektor-Erweiterungen moderner RISC-V-Prozessoren.

Anwendungen sollen so ohne Anpassungen auf unterschiedlichen Prozessorarchitekturen von Beschleunigung profitieren. Möglich macht das unter anderem eine einheitliche Vektor-Codebasis, die verschiedene Befehlssatzerweiterungen wie SSE, AVX, NEON, SVE und RVV über eine gemeinsame Schnittstelle anspricht.

Deutlich ausgebaut wurden die 3D-Funktionen. Das bisherige Modul calib3d teilt sich künftig in die drei Module 3d, calib und stereo auf. Neu hinzu kommen Funktionen für die Kalibrierung mehrerer Kameras, der Import und Export von Punktwolken und Meshes sowie Verfahren zur 3D-Rekonstruktion auf Basis von TSDF-Volumen. Auch moderne Schätzverfahren wie MAGSAC halten Einzug in OpenCV. Diese Erweiterungen richten sich vor allem an Entwickler in der Robotik, von autonomen Systemen und in der industriellen 3D-Vermessung.

Weitere Neuerungen gibt es bei der Bildbearbeitung, die Dokumentation setzt künftig auf eine Kombination aus Sphinx und Doxygen. Den Quellcode stellt das Projekt im GitHub-Repository bereit; die Installation per pip ist ebenfalls vorgesehen.


(fo)



Source link

Weiterlesen

Entwicklung & Code

Angular 22 legt neuen Fokus auf KI-Coding


close notice

This article is also available in
English.

It was translated with technical assistance and editorially reviewed before publication.

Das von Google entwickelte Webframework Angular hat die Hauptversion 22 erreicht. Signal Forms und Angular Aria sowie weitere Features sind nun produktionsreif, und das Angular-Team legt Wert darauf, Angular für den Einsatz mit KI-gestützten Entwicklungstools zu stärken. Dafür sind einige Updates und neue Features mit an Bord.

Weiterlesen nach der Anzeige

Das Feature Signal Forms, im Herbst letzten Jahres in Angular 21 noch experimentell, hat den produktiven Status erreicht. Dabei handelt es sich um eine Bibliothek zum Verwalten von Form-State auf Basis der reaktiven Angular Signals, mitsamt Typsicherheit beim Zugriff auf Formularfelder und zentraler, Schema-basierter Validationslogik. Seit dem letzten Release sind unter anderem eine komplette Dokumentation sowie Support für Angular Material und Angular Aria hinzugekommen.


enterJS 2026

enterJS 2026

(Bild: jaboy / 123rf.com)

Tools und Trends in der JavaScript-Welt: Die enterJS 2026 wird am 16. und 17. Juni in Mannheim stattfinden. Das Programm dreht sich in über 30 Vorträgen rund um das JavaScript-Ökosystem im Enterprise-Umfeld. Ein Angular-Workshop am 15. Juni taucht tief in Signals ein.

Angular Aria ist im neuen Release ebenfalls für den Einsatz in der Produktion geeignet. Die Bibliothek mit Fokus auf Accessibility bietet inzwischen zwölf UI-Pattern, die gängige Barrierefreiheitsaspekte abdecken. Seit Angular 21 neu hinzugekommen sind die vier Pattern Autocomplete, Select, Multiselect und Menubar. Darüber hinaus sind auch die beiden APIs resource und httpResource für asynchrone Reaktivität produktionsreif.

Das Angular-Team hat an einigen Stellschrauben gedreht, um die KI-gestützte Entwicklung mit Angular zu verbessern. So hat der experimentelle Angular-MCP-Server (Model Context Protocol) ein Update erhalten und bietet nun neue Tools, um während des KI-gestützten Erstellens von Anwendungen direkt mit dem Entwicklungsserver zu interagieren. Beispielsweise lässt sich dieser starten (devserver.start) oder stoppen (devserver.stop).

Weiterlesen nach der Anzeige

Zwei entwicklerbezogene Agent-Skills stehen ebenfalls bereit: angular-developer und angular-new-app. Der erste Skill stattet Modelle mit Best-Practices und Richtlinien für das Schreiben moderner Angular-Anwendungen aus, inklusive neuer Features wie Angular Aria und Signal Forms. Der zweite Skill richtet sich an Entwicklerinnen und Entwickler, die Angular zum ersten Mal in einer agentischen Umgebung ausprobieren wollen. Er leitet KI-Assistenten durch die Konfiguration einer lokalen Umgebung für die Angular-Entwicklung.

Alle weiteren Informationen zum neuen Release finden sich im Angular-Blog.


(mai)



Source link

Weiterlesen

Entwicklung & Code

Asynchrone Programmierung – Teil 4: Qt6 mit QPromise und QFuture


close notice

This article is also available in
English.

It was translated with technical assistance and editorially reviewed before publication.

Das Framework Qt unterstützt mit seinem tief in der Architektur verankerten Event-System und dem Signal-Slot-Mechanismus seit jeher Entwicklerinnen und Entwickler bei der asynchronen Programmierung. Diese Möglichkeiten hat der vorangegangene Teil unserer Serie vorgestellt.

Weiterlesen nach der Anzeige


Martin Meeser

Martin Meeser

Martin Meeser ist selbständiger Diplominformatiker (Uni) und bietet Dienstleistungen zum Thema Softwareentwicklung an: Individual-Software-Entwicklung, Beratung zu Prozessen und Schulungen. In zahlreichen Projekten betreute er bisher Kunden unter anderem aus den Bereichen Automotive, Finance, Raumfahrt, Radioastronomie und Medizintechnik.

QFuture ist ein neueres Qt-Konstrukt, das das Konzept des „thennables“ – der .then()-Methoden – aus anderen Sprachen aufnimmt (z. B. Promise in JavaScript, CompletableFuture in Java oder Task in C#). Es erlaubt mit QFuture::then() das Ausführen und Hintereinanderschalten von asynchronen Funktionen, unabhängig von Threads, beispielsweise um Benutzeroberflächen asynchron zu aktualisieren.

In Qt tritt ein lesendes, konsumierendes QFuture immer als die eine Seite der gleichen Medaille auf. Auf der schreibenden, produzierenden Seite steht das QPromise. Entwicklerinnen und Entwickler können den Zustand des Promise-Future-Paares detailliert steuern: starten (QPromise::start()), aussetzen (QPromise::suspend()), beenden (QPromise::finish()) oder abbrechen (QPromise::cancel()). Schließlich können Developer nicht nur einen Rückgabewert, sondern beliebig viele setzen (QPromise::addResult()). Mit der QPromise-/QFuture-API haben sie eine praktische Schnittstelle, um Benutzer- sowie Logik-Schichten effektiv zu trennen und Fortschritte an die Bedienoberfläche zu melden.

Die Klasse QFutureWatcher liefert einen Mechanismus, um die QFuture-Funktionalität mit dem im vorangegangenen Artikel beschriebenen Signal-/Slot-Mechanismus zu verbinden. Das folgende Listing 1 zeigt ein Beispiel für die grundlegenden Funktionsweisen.


int main(int argc, char* argv[])
{
    QCoreApplication app(argc, argv);

    QFutureWatcher watcher;
    QObject::connect(&watcher, &QFutureWatcher::started, []()
    {
        qInfo() << "future started ";
    });

    QObject::connect(&watcher, &QFutureWatcher::resultReadyAt, [&watcher](int i)
    {
        qInfo() << "result ready" << i << "=" << watcher.future().resultAt(i);
    });

    QObject::connect(&watcher, &QFutureWatcher::finished, [&watcher, &app]()
    {
        qInfo() << "future finished ";
        for (int i = 0; i < watcher.future().resultCount(); ++i)
        {
            qInfo() << "Final result" << i << "=" << watcher.future().resultAt(i);
        }
        app.quit();
    });

    QPromise promise;
    QFuture future = promise.future();
    watcher.setFuture(future);

    QThreadPool::globalInstance()->start([&promise]()
    {
        promise.start();
        QThread::sleep(1);
        promise.addResult(10);
        QThread::sleep(1);
        promise.addResult(20);
        QThread::sleep(1);
        promise.finish();
    });

    return app.exec();
}


Listing 1: Einfaches Beispiel für die Verwendung von QPromise, QFuture und QFutureWatcher.

Weiterlesen nach der Anzeige

Neben QFutureWatcher bietet die Klasse QFuture eine Fluent-API an, mit der man Futures hintereinander schaltet (das angesprochene „thennable“ bzw. auch als „chaining“ bezeichnet): Entwickler legen mit then() einen Nachfolger fest, wobei eine zweite Verwendung von then() den bisherigen Nachfolger überschreibt, sodass es immer nur einen Nachfolger geben kann. Außerdem löst die erste Verwendung von addResult des zugrunde liegenden Promise then() aus, und nicht etwa promise.finish(). Ein Abbruch des Promise mit cancel() aktiviert den Callback onCancelled (siehe Listing 2 unten).


int main(int argc, char* argv[])
{
    QCoreApplication app(argc, argv);

    QPromise promise;
    QFuture future = promise.future();

    QThreadPool::globalInstance()->start([&promise]()
    {
        promise.start();
        qInfo() << QDateTime::currentDateTime().toString(Qt::ISODateWithMs) << QThread::currentThreadId() << "started";
        QThread::sleep(1);
        promise.addResult(1);  // triggert then()
        QThread::sleep(1);
        // promise.cancel(); // triggert onCanceled()
        promise.addResult(2); // kein Effekt auf then()
        promise.finish();// kein Effekt auf then()
    });

    future
    .onCanceled([]{/*...*/ return -1;})
    .then([](int result1)
    {
        qInfo() << QDateTime::currentDateTime().toString(Qt::ISODateWithMs) << QThread::currentThreadId() << "result" << result1;
    });


    return app.exec();
}


Listing 2: Beispiel für das Auslösen von then() und onCancelled().

Die Methode then() ist sowohl beim Parameter als auch dem Rückgabewert generisch. Das bedeutet konkret: Bei QFuture hat das then-Callable einen Parameter vom Typ T. Der Rückgabetyp, den der Entwickler innerhalb des then-Callable verwendet, ist der Rückgabetyp des Futures, das wiederum mit then() in die verkettete Abfolge gehängt werden kann, siehe Listing 3:


void myFunc(QString val){/*...*/ return;}


QFuture future = // siehe Listing 12
QFuture future2 = future.then([](int result1)
{
   return QString("fortytwo");
}).then(myFunc);


Listing 3: Beispiel für Future-Chaining mit then().

Falls innerhalb eines Future oder eines then()-Blocks eine Exception auftritt, wird diese an den Callback onFailed() geleitet. Dabei gilt die Regel, dass die Exception in der Kette weiter wandert, bis sie ein passender onFailed-Callback erreicht. Wenn man Programmteile in Arbeiter-Threads auslagert, muss man dort Exceptions korrekt auffangen und an promise.setException() übergeben. Nur dann funktioniert die Methode onFailed wie erwartet, siehe Listing 4:


QThreadPool::globalInstance()->start([&promise]()
    {
        promise.start();

        try
        {
            throw std::runtime_error("error from f1");
            promise.addResult(42); // das wird nicht erreicht
        }
        catch (const std::exception& ex)
        {
            promise.setException(std::current_exception());
        }
    });
    future.then([](int i)
    {
        // ...
    }).onFailed([](const std::exception& ex)
    {
        qInfo() << ex.what();
    });

    QTimer::singleShot(200, &app, &QCoreApplication::quit);


Listing 4: Korrekte Verarbeitung von Exceptions in Arbeits-Threads mit Promise.

Entwickler können auch mehrere onFailed mit einem Future verwenden. In diesem Fall wird das erste passende aufgerufen. Dabei ist die Reihenfolge relevant: Beispielsweise wird in Listing 5 das zweite onFailed nie erreicht, da im vorherigen bereits die darüber liegende Klasse abgefangen wurde.


future.then([](int res) {
    // ...
    throw std::runtime_error("Exception");
}).onFailed([](const std::exception &e) {
    // dieses Callback wird ausgeführt
}).onFailed([](const std::runtime_error &e) {
});


Listing 5: Verwendung mehrerer onFailed-Callbacks

Innerhalb der Funktion, die onFailed verarbeitet, können Entwickler auch einen Rückgabewert angeben. Die Kette wird dann mit diesem Wert fortgeführt, siehe Listing 6:


QFuture future = ...
future
.onFailed([](const QException& ex)
{
    return -1;
})
.then([](int i)
{
    // im Fehlerfall ist i=-1
})


Listing 6: Fortführung der then()-Kette im Fehlerfall.

Wenn kein passender Callback onFailed vorhanden ist, wird die Exception von demjenigen Thread, in dem sie auftrat, an den aufrufenden Thread weitergeleitet und muss dort entsprechend abgefangen werden (Error Propagation), siehe Listing 7:


auto resultFuture = future.then([](int res) {
    ...
    throw Error("message");
    ...
}).onFailed([](const std::exception &e) {
    // wird nicht aufgerufen
}).onFailed([](const QException &e) {
    // wird nicht aufgerufen
});

try {
    auto result = resultFuture.result();
} catch(Error er) {
    // dieser Teil wird aufgerufen
}


Listing 7: Propagation einer Exception.

Die bisher gezeigte Verwendung von then() führt Folgefunktionen standardmäßig in dem Thread aus, in dem das ursprüngliche QFuture lief. Entwickler können aber auch mit einem Parameter den Thread für die Folgefunktion bestimmen. Übergeben sie als Parameter ein QObject, wird dessen zugeordneter QThread verwendet. Bei einen QThreadPoolkommt dieser zum Einsatz.

Schließlich können Developer auch ein Argument vom Typ QtFuture::Launch übergeben: Die weitere Bestimmung Sync entspricht dem beschriebenen Standardfall (gleicher Thread wie Aufrufer), während Async automatisch den globalen Threadpool verwendet und Inherit die Einstellung des Vorgängers, siehe Listing 8:


// Standardfall, kein Parameter, entspricht Sync)
auto f1 = base.then([](int i) { ... });
auto f2 = f1.then(QtFuture::Launch::Sync, [](int i) { ... });

// QObject => Ausführung im Thread des QObjects
auto f3 = f1.then(&obj, [](int i) { ... });

// QThreadPool => Ausführung im angegebenen Pool
auto f4 = f2.then(&customPool, [](int i) { ... });

// Launch::Async => globaler Threadpool
auto f5 = f4.then(QtFuture::Launch::Async, [](int i) { ... });

// Launch::Inherit: erbt Thread des Vorgängers
auto f6 = f5.then(QtFuture::Launch::Inherit, [](int i) { … });


Listing 8: Bestimmung des Threads mit then(…)

Der Namespace QtFuture enthält darüber hinaus einige nützliche Hilfsfunktionen für Futures. Mit den Funktionen QtFuture::makeReady… erstellen Entwicklerinnen und Entwickler ein Future, das bereits im Status beendet ist (QFuture.isFinished() liefert true). makeReadyVoidFuture erzeugt ein beendetes Future ohne Wert (QFuture), makeReadyValueFuture(T) entsprechend ein QFuture und makeReadyRangeFuture ein beendetes QFuture, das mehrere Ergebnisse besitzt. makeExceptionalFuture schließlich erstellt ein beendetes QFuture, das eine Exception beinhaltet.

Diese Funktionen sind nützlich, wenn man bei einer Funktion anhand von Parametern überprüfen möchte, ob eine Bearbeitung als QFuture überhaupt möglich oder sinnvoll ist. Sofern dies nicht der Fall ist, gibt die Funktion direkt ein beendetes QFuture zurück, siehe Listing 9:


QFuture createIntFuture(int a)
{
    if (a <= 0)
    {
        return QtFuture::makeReadyValueFuture(0);
    }

    QPromise promise;
    QFuture result = promise.future();
    QThreadPool::globalInstance()->start([promise = std::move(promise), a]() mutable
    {
        promise.start();
        QThread::sleep(500);
        promise.addResult(a + 1);
        promise.finish();
    });
}


Listing 9: Verwenden eines bei der Erstellung beendeten Futures mit makeReadyValueFuture.

Eine weitere nützliche Funktion ist QtFuture::whenAll(), die ein QFuture erzeugt, das beendet wird, wenn alle als Parameter übergebenen QFuture beendet sind. Die QFuture können verschiedene Template-Typen haben, dementsprechend ist der Rückgabetyp von whenAll ein QFuture mit einer Liste vom Typ std::variant.

Developer müssen hier noch auf die Besonderheit achten, dass beim Chaining mit then() die Nachfolgefunktion auf dem Thread läuft, dessen Future als Letztes beendet wurde. Dies kann, wie bereits beschrieben, ein Parameter für then() explizit festlegen, siehe Listing 10:


QFuture f_int = createIntFuture();
QFuture f_qstring = createStringFuture();
QFuture f_void = createVoidFuture();

using MyFuturesVariant = std::variant, QFuture, QFuture>;

QFuture> f_whenAll = QtFuture::whenAll(f_int, f_qstring, f_void);
f_whenAll.then(/*QtFuture::Launch::Async*/, [](const
    QList& results)
{
    ...
});


Listing 10: Beispiel für QtFuture::whenAll(…)

QtFuture::whenAny() erzeugt ein QFuture, das beendet wird, sobald eines der übergebenen Futures fertig ist. Beim Verketten gilt, dass die Nachfolgefunktion im Thread des zuerst beendeten Futures ausgeführt wird, sofern kein expliziter Launch-Parameter ein anderes bestimmt, siehe Listing 11:


QFuture f_whenAny = QtFuture::whenAny(f_int, f_qstring, f_void);
f_whenAny.then([](const MyFuturesVariant& f)
{

});


Listing 11: Beispiel für QtFuture::whenAny(…)

Schließlich bietet die Funktion QtFuture::connect() die Möglichkeit, aus einem beliebigen Signal ein QFuture zu erzeugen, siehe Listing 12:


QTimer timer(&app);
timer.setInterval(1000);
timer.setSingleShot(true);
timer.start();

QFuture timerTimeoutFuture = QtFuture::connect(&timer, &QTimer::timeout);
timerTimeoutFuture.then([]
{
    qDebug() << "QTimer timeout captured via QtFuture::connect";
});


Listing 12: Beispielhafte Verwendung von QtFuture::connect()



Source link

Weiterlesen

Beliebt