توفر مكتبة QCoro مجموعة من الأدوات للاستفادة من Coroutines C++ 20 مع Qt.
ألقِ نظرة على المثال أدناه لترى مدى روعة الكورتين:
QNetworkAccessManager NetworkAccessManager;// co_انتظار الرد - يتم تعليق coroutine حتى انتهاء QNetworkReply. // أثناء تعليق coroutine، * تعمل حلقة حدث Qt كالمعتاد*.const QNetworkReply *reply = co_await NetworkAccessManager.get(url); // بمجرد الانتهاء من الرد، يستأنف الكود الخاص بك هنا كما لو لم يحدث شيء مذهل للتو؛-)const البيانات التلقائية = الرد->readAll();
يتطلب مترجمًا يدعم couroutines TS، راجع الوثائق للحصول على قائمة بالمترجمين والإصدارات المدعومة.
التوثيق
يوفر QCoro الأدوات اللازمة لتسهيل استخدام كوروتينات C++20 مع Qt. حجر الزاوية في المكتبة هو QCoro::Task<T>
، والذي يمثل كوروتين تم تنفيذه ويسمح للمتصل بانتظار نتيجة الكوروتين بشكل غير متزامن. بالإضافة إلى ذلك، يوفر QCoro مجموعة من الأغلفة لأنواع Qt الشائعة، مثل QTimer
و QNetworkReply
و QDBusPendingCall
و QFuture
وغيرها، والتي تسمح بالانتظار co_await
لعملياتهم غير المتزامنة مباشرةً.
بالإضافة إلى ذلك، هناك وظيفة qCoro()
السحرية التي يمكنها تغليف العديد من وظائف وأنواع Qt الأصلية لجعلها صديقة للروتين.
اذهب للتحقق من الوثائق للحصول على قائمة كاملة بجميع الميزات المدعومة وأنواع Qt.
QDBusPendingCall
يمكن لـ QCoro الانتظار حتى انتهاء مكالمة D-Bus غير المتزامنة. ليست هناك حاجة لاستخدام QDBusPendingCallWatcher
مع QCoro - فقط co_await
النتيجة بدلاً من ذلك. أثناء الانتظار المشترك، تعمل حلقة حدث Qt كالمعتاد.
QDBusInterface RemoteServiceInterface{serviceName, objectPath, Interface};const QDBusReply<bool> isReady = co_await RemoteServiceInterface.asyncCall(QStringLiteral("isReady"));
التوثيق الكامل هنا .
QFuture
يمثل QFuture نتيجة لمهمة غير متزامنة. عادةً يتعين عليك استخدام QFutureWatcher
للحصول على إشعار عندما يكون المستقبل جاهزًا. مع QCoro، يمكنك فقط 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 أ + ب؛
التوثيق الكامل هنا .
QNetworkReply
قد يكون تنفيذ طلبات الشبكة باستخدام Qt أمرًا مملاً - فأسلوب الإشارة/الفتحة يقطع تدفق التعليمات البرمجية الخاصة بك. سرعان ما تصبح طلبات التسلسل ومعالجة الأخطاء فوضوية ويتم تقسيم التعليمات البرمجية الخاصة بك إلى وظائف عديدة. ولكن ليس مع QCoro، حيث يمكنك ببساطة co_await
حتى انتهاء QNetworkReply
:
QNetworkAccessManager qnam; QNetworkReply *reply = qnam.get(QStringLiteral("https://github.com/qcoro/qcoro"));const auto content = co_await Response; الرد->deleteLater();if (reply->error()!= QNetworkReply::NoError) {co_return HandleError(reply); }const auto link = findLinkInReturnedHtmlCode(contents); الرد = qnam.get(link);const auto data = co_await الرد; الرد->deleteLater();if (reply->error()!= QNetworkReply::NoError) {co_return HandleError(reply); } ...
التوثيق الكامل هنا .
QTimer
ربما تريد تأخير تنفيذ التعليمات البرمجية الخاصة بك لمدة ثانية، وربما ترغب في تنفيذ بعض التعليمات البرمجية في فترات زمنية متكررة. يصبح هذا أمرًا تافهًا للغاية مع co_await
:
توقيت كيوتايمر؛ timer.setInterval(1s); timer.start();for (int i = 1; i <= 100; ++i) {co_await timer;qDebug() << "في انتظار " << i << " ثانية..."; }qDebug() << "تم!";
التوثيق الكامل هنا .
QIODevice
QIODevice
هي فئة أساسية للعديد من فئات Qt التي تسمح بكتابة البيانات وقراءتها بشكل غير متزامن. كيف تعرف أن هناك بيانات جاهزة للقراءة؟ يمكنك الاتصال بـ QIODevice::readyRead()
سينغال، أو يمكنك استخدام QCoro co_await
الكائن:
المقبس->write("PING");// في انتظار "pong"const auto data = co_awaitocket;co_returncalculateLatency(data);
التوثيق الكامل هنا .
اذهب للتحقق من الوثائق الكاملة لمعرفة المزيد.
في بعض الأحيان لا يكون من الممكن استخدام co_await
للتعامل مع نتيجة coroutine - عادةً عند التفاعل مع رمز جهة خارجية لا يدعم coroutines. في هذه السيناريوهات، من الممكن ربط رد اتصال مستمر بالكوروتين والذي سيتم استدعاؤه بشكل غير متزامن عند انتهاء الكوروتين.
void RegularFunction() {someCoroutineReturningInt().then([](int result) {// Handle result}); }
يمكن أيضًا أن يكون رد الاتصال المستمر بمثابة coroutine وتكون نتيجة التعبير بأكمله هي Task حيث T هو نوع الإرجاع للاستمرار. بفضل ذلك، من الممكن أن co_await
السلسلة بأكملها، أو أن نستمر في سلسلة متعددة .then()
.
التوثيق الكامل هنا .
المولد عبارة عن كوروتين ينتج قيمًا متعددة بتكاسل. على الرغم من عدم وجود شيء خاص بـ Qt، فإن QCoro يوفر الأدوات اللازمة للمستخدمين لإنشاء مولدات مخصصة في تطبيقات Qt الخاصة بهم.
يوفر QCoro واجهة برمجة التطبيقات (API) لكل من المولدات المتزامنة ( QCoro::Generator<T>
) والمولدات غير المتزامنة ( QCoro::AsyncGenerator<T>
). يوفر كلا المولدين واجهة برمجة تطبيقات تشبه الحاوية: وظائف الأعضاء begin()
و end()
التي تُرجع كائنات تشبه المكرر، وهي واجهة برمجة تطبيقات معروفة وراسخة وتجعل المولدات متوافقة مع الخوارزميات الموجودة.
QCoro::Generator<int> فيبوناتشي() { quint64 أ = 0، ب = 0؛ Q_FOREVER {co_yield b;const auto tmp = b; أ = ب؛ ب += تمة؛ } } void printFib(quint64 max) {for (auto fib : fibonacci()) {if (fib > max) {break; } std::cout << fib << std::endl; } }
التوثيق الكامل هنا .
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.