La biblioteca QCoro proporciona un conjunto de herramientas para utilizar corrutinas de C++20 con Qt.
Eche un vistazo al siguiente ejemplo para ver lo sorprendentes que son las corrutinas:
QNetworkAccessManager networkAccessManager;// co_await la respuesta: la corrutina se suspende hasta que finalice QNetworkReply.// Mientras la corrutina está suspendida, *el bucle de eventos de Qt se ejecuta como de costumbre*.const QNetworkReply *reply = co_await networkAccessManager.get(url); // Una vez finalizada la respuesta, tu código se reanuda aquí como si nada sorprendente acabara de suceder ;-)const datos automáticos = responder->readAll();
Requiere un compilador compatible con las rutinas TS; consulte la documentación para obtener una lista de compiladores y versiones compatibles.
Documentación
QCoro proporciona las herramientas necesarias para facilitar el uso de las corrutinas de C++20 con Qt. La piedra angular de la biblioteca es QCoro::Task<T>
, que representa una corrutina ejecutada y permite que la persona que llama espere asincrónicamente el resultado de la corrutina. Además, QCoro proporciona un conjunto de contenedores para tipos Qt comunes, como QTimer
, QNetworkReply
, QDBusPendingCall
, QFuture
y otros, que permiten co_await
sus operaciones asincrónicas directamente.
Además, existe una función mágica qCoro()
que puede encapsular muchas funciones y tipos nativos de Qt para que sean compatibles con las rutinas.
Consulte la documentación para obtener una lista completa de todas las funciones compatibles y tipos de Qt.
QDBusPendingCall
QCoro puede esperar a que finalice una llamada asincrónica de D-Bus. No es necesario utilizar QDBusPendingCallWatcher
con QCoro; en su lugar, simplemente co_await
el resultado. Mientras co_awaiting, el bucle de eventos de Qt se ejecuta como de costumbre.
QDBusInterface RemoteServiceInterface {nombre del servicio, ruta del objeto, interfaz}; const QDBusReply<bool> isReady = co_await remoteServiceInterface.asyncCall(QStringLiteral("isReady"));
Documentación completa aquí.
QFuture
QFuture representa el resultado de una tarea asincrónica. Normalmente tienes que usar QFutureWatcher
para recibir notificaciones cuando el futuro esté listo. ¡Con QCoro, puedes simplemente co_await
!
const QFuture<int> tarea1 = QtConcurrent::run(....);const QFuture<int> tarea2 = QtConcurrent::run(....);const int a = co_await tarea1;const int b = co_await tarea2; co_retorno a + b;
Documentación completa aquí.
QNetworkReply
Realizar solicitudes de red con Qt puede ser tedioso: el enfoque de señal/ranura interrumpe el flujo de su código. El encadenamiento de solicitudes y el manejo de errores rápidamente se vuelven complicados y su código se divide en numerosas funciones. Pero no con QCoro, donde simplemente puede co_await
que QNetworkReply
finalice:
QNetworkAccessManager qnam; QNetworkReply *reply = qnam.get(QStringLiteral("https://github.com/qcoro/qcoro"));const auto contenido = co_await respuesta; responder->deleteLater();if (respuesta->error() != QNetworkReply::NoError) {co_return handleError(respuesta); }enlace automático constante = findLinkInReturnedHtmlCode(contenido); respuesta = qnam.get(enlace);const auto data = co_await respuesta; responder->deleteLater();if (respuesta->error() != QNetworkReply::NoError) {co_return handleError(respuesta); } ...
Documentación completa aquí.
QTimer
Tal vez desee retrasar la ejecución de su código por un segundo, tal vez desee ejecutar algún código en intervalos repetidos. Esto se vuelve súper trivial con co_await
:
Temporizador QTimer; temporizador.setInterval(1s); timer.start();for (int i = 1; i <= 100; ++i) {co_await timer;qDebug() << "Esperando " << i << " segundos..."; }qDebug() << "¡Listo!";
Documentación completa aquí.
QIODevice
QIODevice
es una clase base para muchas clases en Qt que permiten escribir y leer datos de forma asincrónica. ¿Cómo sabes que hay datos listos para ser leídos? Puede conectarse a la señal QIODevice::readyRead()
, o puede usar QCoro y co_await
el objeto:
socket->write("PING");// Esperando "pong"const auto data = co_await socket;co_return calcularLatency(data);
Documentación completa aquí.
Consulte la documentación completa para obtener más información.
A veces no es posible usar co_await
para manejar el resultado de una corrutina, generalmente cuando se interactúa con un código de terceros que no admite corrutinas. En esos escenarios, es posible encadenar una devolución de llamada de continuación a la rutina que se invocará de forma asíncrona cuando finalice la rutina.
void regularFunction() {someCoroutineReturningInt().then([](int resultado) {// manejar resultado}); }
La devolución de llamada de continuación también puede ser una corrutina y el resultado de la expresión completa es Tarea donde T es el tipo de retorno de la continuación. Gracias a eso, es posible co_await
toda la cadena o encadenar múltiples continuaciones .then()
.
Documentación completa aquí.
Generator es una rutina que produce múltiples valores de forma perezosa. Si bien no hay nada específico de Qt, QCoro proporciona las herramientas necesarias para que los usuarios creen generadores personalizados en sus aplicaciones Qt.
QCoro proporciona API tanto para generadores síncronos ( QCoro::Generator<T>
) como para generadores asíncronos ( QCoro::AsyncGenerator<T>
). Ambos generadores proporcionan API tipo contenedor: funciones miembro begin()
y end()
que devuelven objetos tipo iterador, que es una API bien conocida y establecida y hace que los generadores sean compatibles con los algoritmos existentes.
QCoro::Generador<int> fibonacci() { quint64 a = 0, b = 0; Q_FOREVER {co_yield b;const auto tmp = b; a = b; b += tmp; } }void printFib(quint64 max) {for (auto fib : fibonacci()) {si (fib > max) {break; } std::cout << fib << std::endl; } }
Documentación completa aquí.
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.