QCoro 函式庫提供了一組工具來將 C++20 協程與 Qt 結合使用。
看看下面的例子,你就會知道協程是多麼神奇的事:
QNetworkAccessManager networkAccessManager;// co_await 回覆 - 協程被掛起,直到 QNetworkReply 完成。回覆完成後,您的程式碼將在此處恢復,就好像沒有發生任何令人驚奇的事情一樣;-)const auto data =reply->readAll();
它需要一個支援協程 TS 的編譯器,請參閱文件以取得支援的編譯器和版本的清單。
文件
QCoro 提供了在 Qt 中輕鬆使用 C++20 協程所需的工具。該函式庫的基石是QCoro::Task<T>
,它表示一個已執行的協程,並允許其呼叫者非同步等待協程的結果。此外,QCoro 還為常見的 Qt 類型提供了一組包裝器,例如QTimer
、 QNetworkReply
、 QDBusPendingCall
、 QFuture
等,允許直接co_await
非同步操作。
此外,還有一個神奇的qCoro()
函數,可以包裝許多本機 Qt 函數和類型,使它們對協程友好。
請查看文件以取得所有支援的功能和 Qt 類型的完整清單。
QDBusPendingCall
QCoro 可以等待非同步 D-Bus 呼叫完成。無需將QDBusPendingCallWatcher
與 QCoro 一起使用 - 只需co_await
結果即可。在 co_awaiting 期間,Qt 事件循環照常運作。
QDBusInterface remoteServiceInterface{serviceName, objectPath, 介面};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 a + b;
完整文件在這裡。
QNetworkReply
使用 Qt 執行網路請求可能會很乏味 - 訊號/槽方法會破壞程式碼流程。連結請求和錯誤處理很快就會變得混亂,並且您的程式碼被分解為許多函數。但 QCoro 則不然,您可以簡單地co_await
QNetworkReply
完成:
QNetworkAccessManager qnam; QNetworkReply *reply = qnam.get(QStringLiteral("https://github.com/qcoro/qcoro"));const autocontents = co_awaitreply; 回覆->deleteLater();if (回覆->error() != QNetworkReply::NoError) {co_return handleError(reply); }const 自動連結 = findLinkInReturnedHtmlCode(內容); 回覆 = qnam.get(link);const auto data = co_await 回覆; 回覆->deleteLater();if (回覆->error() != QNetworkReply::NoError) {co_return handleError(reply); } …
完整文件在這裡。
QTimer
也許您想延遲執行程式碼一秒鐘,也許您想以重複的間隔執行某些程式碼。這對co_await
來說變得非常簡單:
QTimer定時器; 定時器.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
物件:
socket->write("PING");// 等待「pong」 const auto data = co_await socket;co_returncalculateLatency(data);
完整文件在這裡。
請查看完整文件以了解更多資訊。
有時不可能使用co_await
來處理協程的結果 - 通常是在與不支援協程的第三方程式碼互動時。在這些場景中,可以將連續回呼連結到協程,當協程完成時,該回呼將會被非同步呼叫。
void RegularFunction() {someCoroutineReturningInt().then([](int result) {// 處理結果}); }
延續回呼也可以是協程,整個表達式的結果是 Task,其中 T 是延續的回傳類型。因此,可以co_await
整個鏈,或連結多個.then()
延續。
完整文件在這裡。
生成器是一個延遲產生多個值的協程。雖然沒有任何特定於 Qt 的內容,但 QCoro 為使用者提供了必要的工具,以便在其 Qt 應用程式中建立自訂生成器。
QCoro 為同步產生器 ( QCoro::Generator<T>
) 和非同步產生器 ( QCoro::AsyncGenerator<T>
) 提供 API。兩個生成器都提供類似容器的 API: begin()
和end()
成員函數傳回類似迭代器的對象,這是眾所周知且已建立的 API,並使生成器與現有演算法相容。
QCoro::Generator<int> 斐波那契() { 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()) {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.