La bibliothèque QCoro fournit un ensemble d'outils pour utiliser les coroutines C++20 avec Qt.
Jetez un œil à l’exemple ci-dessous pour voir à quel point les coroutines sont étonnantes :
QNetworkAccessManager networkAccessManager;// co_await la réponse - la coroutine est suspendue jusqu'à ce que QNetworkReply soit terminée.// Pendant que la coroutine est suspendue, *la boucle d'événements Qt s'exécute comme d'habitude*.const QNetworkReply *reply = co_await networkAccessManager.get(url); // Une fois la réponse terminée, votre code reprend ici comme si de rien d'extraordinaire ne venait de se produire ;-)const auto data = réponse->readAll();
Il nécessite un compilateur prenant en charge les couroutines TS, voir la documentation pour une liste des compilateurs et des versions pris en charge.
Documentation
QCoro fournit les outils nécessaires pour utiliser facilement les coroutines C++20 avec Qt. La pierre angulaire de la bibliothèque est QCoro::Task<T>
, qui représente une coroutine exécutée et permet d'attendre de manière asynchrone le résultat de la coroutine par son appelant. De plus, QCoro fournit un ensemble de wrappers pour les types Qt courants, tels que QTimer
, QNetworkReply
, QDBusPendingCall
, QFuture
et autres, qui permettent de co_await
directement leurs opérations asynchrones.
De plus, il existe une fonction magique qCoro()
qui peut envelopper de nombreuses fonctions et types natifs de Qt pour les rendre compatibles avec la coroutine.
Allez consulter la documentation pour une liste complète de toutes les fonctionnalités et types Qt pris en charge.
QDBusPendingCall
QCoro peut attendre la fin d'un appel D-Bus asynchrone. Il n'est pas nécessaire d'utiliser QDBusPendingCallWatcher
avec QCoro - il suffit co_await
le résultat à la place. Pendant co_awaiting, la boucle d'événements Qt s'exécute comme d'habitude.
QDBusInterface remoteServiceInterface{serviceName, objectPath, interface};const QDBusReply<bool> isReady = co_await remoteServiceInterface.asyncCall(QStringLiteral("isReady"));
Documentation complète ici.
QFuture
QFuture représente le résultat d'une tâche asynchrone. Normalement, vous devez utiliser QFutureWatcher
pour être averti lorsque l'avenir est prêt. Avec QCoro, vous pouvez simplement l' co_await
!
const QFuture<int> task1 = QtConcurrent::run(....);const QFuture<int> task2 = QtConcurrent::run(....);const int a = co_await task1;const int b = co_await task2; co_return a + b;
Documentation complète ici.
QNetworkReply
Faire des requêtes réseau avec Qt peut être fastidieux - l'approche signal/slot interrompt le flux de votre code. Le chaînage des requêtes et la gestion des erreurs deviennent rapidement un gâchis et votre code est divisé en de nombreuses fonctions. Mais pas avec QCoro, où vous pouvez simplement co_await
la fin de QNetworkReply
:
QNetworkAccessManager qnam; QNetworkReply *reply = qnam.get(QStringLiteral("https://github.com/qcoro/qcoro"));const auto contents = co_await réponse; réponse->deleteLater();if (réponse->erreur() != QNetworkReply::NoError) {co_return handleError(réponse); }const lien automatique = findLinkInReturnedHtmlCode(contents); réponse = qnam.get(lien);const auto data = co_await réponse; réponse->deleteLater();if (réponse->erreur() != QNetworkReply::NoError) {co_return handleError(réponse); } ...
Documentation complète ici.
QTimer
Peut-être souhaitez-vous retarder l'exécution de votre code d'une seconde, peut-être souhaitez-vous exécuter du code à intervalles répétés. Cela devient super trivial avec co_await
:
Minuterie QTimer ; minuterie.setInterval(1s); timer.start();for (int i = 1; i <= 100; ++i) {co_await timer;qDebug() << "En attente de " << i << " secondes..."; }qDebug() << "Terminé !";
Documentation complète ici.
QIODevice
QIODevice
est une classe de base pour de nombreuses classes de Qt qui permettent d'écrire et de lire des données de manière asynchrone. Comment savoir qu'il y a des données prêtes à être lues ? Vous pouvez vous connecter au singulier QIODevice::readyRead()
, ou vous pouvez utiliser QCoro et co_await
l'objet :
socket->write("PING");// En attente de "pong"const auto data = co_await socket;co_return calculateLatency(data);
Documentation complète ici.
Allez consulter la documentation complète pour en savoir plus.
Parfois, il n'est pas possible d'utiliser co_await
pour gérer le résultat d'une coroutine - généralement lors de l'interface avec un code tiers qui ne prend pas en charge les coroutines. Dans ces scénarios, il est possible de chaîner un rappel de continuation à la coroutine qui sera invoqué de manière asynchrone lorsque la coroutine se terminera.
void régularFunction() {someCoroutineReturningInt().then([](int result) {// handle result}); }
Le rappel de continuation peut également être une coroutine et le résultat de l'expression entière est Task où T est le type de retour de la continuation. Grâce à cela, il est possible de co_await
toute la chaîne, ou d'enchaîner plusieurs continuations .then()
.
Documentation complète ici.
Generator est une coroutine qui produit paresseusement plusieurs valeurs. Bien qu'il n'y ait rien de spécifique à Qt, QCoro fournit les outils nécessaires aux utilisateurs pour créer des générateurs personnalisés dans leurs applications Qt.
QCoro fournit une API pour les générateurs synchrones ( QCoro::Generator<T>
) et les générateurs asynchrones ( QCoro::AsyncGenerator<T>
). Les deux générateurs fournissent une API de type conteneur : les fonctions membres begin()
et end()
qui renvoient des objets de type itérateur, ce qui est une API bien connue et établie et rend les générateurs compatibles avec les algorithmes existants.
QCoro::Générateur<int> fibonacci() { quint64 a = 0, b = 0; Q_FOREVER {co_yield b;const auto tmp = b; une = b; b += tmp; } }void printFib(quint64 max) {for (auto fib : fibonacci()) {if (fib > max) {break; } std :: cout << fib << std :: endl; } }
Documentation complète ici.
MIT License
Copyright (c) 2022 Daniel Vrátil <[email protected]>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.