C++中的鏈式操作原理與應用(三):專注于異步操作延的C++開源庫 continuable

目錄

1.簡介

2.安裝與集成

3.快速入門

4.完整示例

5.優勢與適用場景


1.簡介

????????continuable?是一個專注于?異步操作延續(continuation)?的現代 C++ 開源庫,旨在簡化異步編程流程,解決 “回調地獄” 問題,提供直觀、靈活的異步操作鏈式調用和組合能力。它的設計理念類似于 JavaScript 中的?Promise,但更貼合 C++ 語法特性和現代標準(C++11 及以上)。

????????異步編程中,多個依賴的異步操作(如網絡請求、文件 IO)常導致嵌套回調(“回調地獄”),代碼可讀性和維護性極差。continuable?通過?延續傳遞風格(Continuation-Passing Style)?封裝異步操作,允許將異步操作的 “后續處理邏輯”(延續)通過鏈式調用串聯,使異步流程更接近同步代碼的線性結構。

????????主要特性有:

  1. 鏈式延續:通過?then()?方法串聯異步操作,前一個操作的結果自動傳遞給下一個延續。
  2. 錯誤處理:統一的錯誤傳播機制,通過?catch_()?捕獲鏈中任意環節的錯誤。
  3. 操作組合:支持并行(when_all())、串行(when_seq())等方式組合多個異步操作。
  4. 多范式兼容:可與回調函數、std::future、協程(C++20)等多種異步模型集成。
  5. 輕量級:header-only 庫(僅需包含頭文件),無外部依賴,易于集成。
  6. 類型安全:通過模板推導自動處理參數類型,編譯期檢查類型匹配。

2.安裝與集成

continuable?是?header-only?庫,無需編譯,只需:

1.從?GitHub 倉庫?下載源碼或從網站下載壓縮包。

https://github.com/Naios/continuable

2.將?include?目錄添加到項目包含路徑。

3.包含核心頭文件?#include "continuable/continuable.hpp"?即可使用。

支持 C++11 及以上標準,兼容主流編譯器(GCC、Clang、MSVC)。

注意:continuable依賴asio和function2庫

asio庫源碼的下載地址:

Downloading Asio

function2的引用可參考:

function2:一個專注于函數對象包裝的現代 C++ 開源庫-CSDN博客

3.快速入門

1.通過make_continuable創建一個可延續對象,該對象在調用時會返回一個承諾

auto http_request(std::string url) {return cti::make_continuable<std::string>([url = std::move(url)](auto&& promise) {// Perform the actual request through a different library,// resolve the promise upon completion of the task.promise.set_value("<html> ... </html>");// or: promise.set_exception(std::make_exception_ptr(std::exception("Some error")));// or: promise.set_canceled();});
}auto mysql_query(std::string query) {return cti::make_continuable<result_set, bool>([url = std::move(url)](auto&& promise) {//                         ^^^^^^^^^^^^^^ multiple result types});
}auto do_sth() {return cti::make_continuable<void>([](auto&& promise) {//                         ^^^^ no result at all});
}auto run_it() {return async([] {// Directly start with a handler});
}continuable<> run_it() { // With type erasurereturn async([] {});
}

2.通過then附加您的延續,支持多個結果和部分處理程序:

mysql_query("SELECT `id`, `name` FROM `users`").then([](result_set users) {// Return the next continuable to process ...return mysql_query("SELECT `id` name FROM `sessions`");}).then([](result_set sessions) {// ... or pass multiple values to the next callback using tuples or pairs ...return std::make_tuple(std::move(sessions), true);}).then([](result_set sessions, bool is_ok) {// ... or pass a single value to the next callback ...return 10;}).then([](auto value) {//     ^^^^ Templated callbacks are possible too})// ... you may even pass continuables to the `then` method directly:.then(mysql_query("SELECT * `statistics`")).then([](result_set result) {// ...return "Hi";}).then([] /*(std::string result) */ { // Handlers can accept a partial set of arguments{// ...});

3.通過failnext處理故障:

http_request("example.com").then([] {throw std::exception("Some error");}).fail([] (std::exception_ptr ptr) {if (ptr) {try {std::rethrow_exception(ptr);} catch(std::exception const& e) {// Handle the exception or error code here}}});

4.通過特定的執行器調度延續(可能在不同的線程上或稍后)

auto executor = [](auto&& work) {// Dispatch the work here, store it for later invocation or move it to another thread.std::forward<decltype(work)>(work)();
};read_file("entries.csv").then([](Buffer buffer) {// ...}, executor);
//   ^^^^^^^^

5.通過when_allwhen_anywhen_seq連接可延續對象:

// `all` of connections:
(http_request("github.com") && http_request("example.com") && http_request("wikipedia.org")).then([](std::string github, std::string example, std::string wikipedia) {// The callback is called with the response of github,// example and wikipedia.});// `any` of connections:
(http_request("github.com") || http_request("example.com") || http_request("wikipedia.org")).then([](std::string github_or_example_or_wikipedia) {// The callback is called with the first response of either github,// example or wikipedia.});// `sequence` of connections:
(http_request("github.com") >> http_request("example.com") >> http_request("wikipedia.org")).then([](std::string github, std::string example, std::string wikipedia) {// The requests are invoked sequentially});// Mixed logical connections:
(http_request("github.com") && (http_request("example.com") || http_request("wikipedia.org"))).then([](std::string github, std::string example_or_wikipedia) {// The callback is called with the response of github for sure// and the second parameter represents the response of example or wikipedia.});// There are helper functions for connecting continuables:
auto all = cti::when_all(http_request("github.com"), http_request("example.com"));
auto any = cti::when_any(http_request("github.com"), http_request("example.com"));
auto seq = cti::when_seq(http_request("github.com"), http_request("example.com"));

6.通過result處理多個結果變量,并通過recover從故障中恢復:

make_exceptional_continuable<void>(std::make_exception_ptr(std::exception("Some error")).fail([] (std::exception_ptr ptr) {return recover();}).then([] () -> result<> {// We recovered from the failure and proceeding normally// Will yield a default constructed exception type to signal cancellationreturn cancel();});

7.對現有代碼進行“promisify”處理,或使用(asio)完成令牌集成:

// Promisification of your existing code that accepts callbacks
auto async_resolve(std::string host, std::string service) {return cti::promisify<asio::ip::udp::resolver::iterator>::from([&](auto&&... args) {resolver_.async_resolve(std::forward<decltype(args)>(args)...);},std::move(host), std::move(service));
}// (boost) asio completion token integration
asio::io_context io_context;
asio::steady_timer steady_timer(io_context);steady_timer.expires_after(std::chrono::seconds(5));
steady_timer.async_wait(cti::use_continuable).then([] {// Is called after 5s});

4.完整示例

continuable?是一個?header-only?庫(僅需包含頭文件,無需編譯庫本身),因此使用 CMake 配置項目時,只需指定頭文件路徑和 C++ 標準即可。以下是詳細的 CMake 配置步驟和示例:

1.假設項目結構如下(將?continuable?作為第三方庫放在項目中):

2.CMakeLists.txt 配置

核心配置包括:指定 C++ 標準(需 C++11 及以上)、添加?continuable?的頭文件路徑。

# 最低CMake版本要求
cmake_minimum_required(VERSION 3.10)# 項目名稱和版本
project(continuable_demo VERSION 1.0)# 指定C++標準(continuable需要C++11及以上)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF) # 禁用編譯器擴展# 添加continuable的頭文件路徑
# 假設continuable放在third_party目錄下
#target_include_directories(continuable_demo
#  PRIVATE
#    ${CMAKE_CURRENT_SOURCE_DIR}/third_party/continuable/include
#)message(STATUS "continuable directories: ${CMAKE_CURRENT_SOURCE_DIR}")include_directories(${CMAKE_CURRENT_SOURCE_DIR}/third_party/include${CMAKE_CURRENT_SOURCE_DIR}/third_party/include/dep/function2/include
)# 添加源文件
add_executable(continuable_demosrc/main.cpp
)

3.示例代碼(src/main.cpp)

編寫一個簡單的異步操作示例,驗證配置是否正確:

#include <iostream>
#include <thread>
#include <chrono>
// 引入continuable頭文件
#include "continuable/continuable.hpp"// 模擬異步操作:1秒后返回一個整數
auto async_operation(int value) {return cti::make_continuable<int>([value](auto&& promise) {// 在新線程中執行異步操作std::thread([value, promise = std::forward<decltype(promise)>(promise)]() mutable {std::this_thread::sleep_for(std::chrono::seconds(1)); // 模擬耗時操作promise.set_value(value * 2); // 異步操作結果}).detach();});
}int main() {std::cout << "開始異步操作..." << std::endl;// 鏈式調用異步操作async_operation(5).then([](int result) {std::cout << "第一步結果: " << result << "(5*2)" << std::endl;return async_operation(result); // 傳遞結果到下一個異步操作}).then([](int result) {std::cout << "第二步結果: " << result << "(10*2)" << std::endl;})/*.catch_([](const std::exception& e) {std::cerr << "錯誤: " << e.what() << std::endl;})*/;// 等待異步操作完成(實際項目中用事件循環替代)std::this_thread::sleep_for(std::chrono::seconds(3));return 0;
}

4.編譯步驟

mkdir build && cd build
cmake ..          # 生成Makefile
cmake --build . --config Debug             # 編譯項目
.\Debug\continuable_demo # 運行程序

5.關鍵說明

1)header-only 特性

continuable?無需編譯為靜態庫或動態庫,只需在 CMake 中通過?target_include_directories?指定其頭文件路徑即可。

2)C++ 標準

必須指定?CMAKE_CXX_STANDARD 11?或更高(如 C++14、C++17),否則會因語法不兼容導致編譯錯誤。

3)跨平臺兼容性

上述配置兼容 Windows(MSVC)、Linux(GCC/Clang)、macOS,只需確保編譯器支持 C++11 及以上標準。

6.完整源碼下載地址

通過網盤分享的文件:continuableTest.zip
鏈接: https://pan.baidu.com/s/1MkrlvYChgIWr2boGnwD4_g?pwd=1234 提取碼: 1234

5.優勢與適用場景

  • 簡化異步流程:將嵌套回調轉為線性鏈式調用,代碼更易讀、維護。
  • 靈活組合:支持串行、并行等復雜異步工作流,滿足多任務依賴場景。
  • 現代 C++ 友好:充分利用模板、lambda、移動語義等特性,類型安全且高效。

適用于需要處理大量異步操作的場景:網絡編程(如 HTTP 請求、RPC 調用)、文件 IO、異步數據庫操作等。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/93013.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/93013.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/93013.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

STM32--寄存器與標準庫函數--通用定時器--輸出比較(PWM生成)

目錄 前言 通用定時器類型 向上計數、向下計數、中心對齊 輸入捕獲與輸出比較概念 輸出比較典型例子&#xff1a;驅動舵機旋轉 通用定時器的輸出比較庫函數 代碼 通用定時器的輸出比較寄存器操作 代碼 這里提供數據手冊的寄存器 后言 前言 使用平臺:STM32F407ZET6 使…

91、23種設計模式

設計模式是軟件設計中反復出現的解決方案的模板&#xff0c;用于解決特定問題并提高代碼的可維護性、可擴展性和可復用性。23種經典設計模式可分為創建型、結構型和行為型三大類&#xff0c;以下是具體分類及模式概述&#xff1a; 一、創建型模式&#xff08;5種&#xff09; 關…

力扣(串聯所有單詞的子串)

串聯所有單詞的子串問題&#xff1a;多滑動窗口與哈希表的實戰應用。 一、題目分析&#xff08;一&#xff09;問題定義 給定字符串 s 和字符串數組 words&#xff08;words 中所有單詞長度相同 &#xff09;&#xff0c;找出 s 中所有“串聯子串”的起始索引。串聯子串指包含 …

RH134 管理基本存儲知識點

1. 對 Linux 磁盤進行分區時有哪兩種方案&#xff1f;分別加以詳細說明。答&#xff1a;MBR分區&#xff1a;主引導記錄(MBR)分區方案是運行BIOS固件的系統上的標準方案。此方案支持最 多四個主分區。在Linux系統上&#xff0c;您可以使用擴展分區和邏輯分區來創建最多…

【JS 異步】告別回調地獄:Async/Await 和 Promise 的優雅實踐與錯誤處理

【JS 異步】告別回調地獄&#xff1a;Async/Await 和 Promise 的優雅實踐與錯誤處理 所屬專欄&#xff1a; 《前端小技巧集合&#xff1a;讓你的代碼更優雅高效 上一篇&#xff1a; 【JS 數組】數組操作的“瑞士軍刀”&#xff1a;精通 Array.reduce() 的騷操作 作者&#xff…

23.Linux : ftp服務及配置詳解

Linux &#xff1a; ftp服務及配置詳解 FTP 基本概念 定義&#xff1a;文件傳輸協議&#xff08;File Transfer Protocol&#xff09;&#xff0c;采用 C/S 模式工作。端口&#xff1a; 控制端口&#xff1a;21數據端口&#xff1a;20FTP 工作原理模式工作流程連接發起方主動模…

悲觀鎖樂觀鎖與事務注解在項目實戰中的應用場景及詳細解析

在今天做的項目練習部分中真的學到了很多東西&#xff0c;也補充了許多之前遺漏或是忘記的知識點&#xff0c;但時間精力有限&#xff0c;我就先記錄一下今天用到的一個新東西&#xff0c;悲觀鎖和樂觀鎖。首先給出實際應用背景&#xff1a;在加入鎖和事務注解之前&#xff0c;…

Java構造器與工廠模式(靜態工程方法)詳解

1. 構造器1.1 構造器的核心意義1.1.1 對象初始化構造器在創建對象 (new) 時自動調用, 用于初始化對象的狀態 (如設置字段初始值, 分配資源等)無構造器時: 字段為默認值&#xff08;0/null/false&#xff09;有構造器&#xff1a;確保對象創建后即處于有效狀態1.1.2 強制初始化…

解決jdk初始化運行,防火墻通信選錯專業網絡問題

問題描述新項目添加不同版本的jdk&#xff0c;運行時提示防火墻通信策略&#xff0c;選成專用網絡。其他人訪問后端接口時&#xff0c;提示連接失敗。 解決方案&#xff1a;1、在搜索欄中輸入 防火墻關鍵字&#xff0c;選擇到防火墻和網絡保護2、選擇允許應用通過防火墻3、先點…

【Linux】常用命令(三)

【Linux】常用命令&#xff08;三&#xff09;1. export1.1 原理1.2 常用語法1.3 示例1.4 書中對命令的解釋1.5 生效范圍2. 測試服務地址與其端口能否訪問2.1 nc(Netcat)命令2.2 telnet2.3 nmap2.4 curl命令 (適用于HTTP/HTTPS 服務)1. export export 是 Linux Shell&#xff…

Pytest項目_day15(yaml)

YAMLYAML是一個對所有編程語言都很友好的數據序列化標準&#xff0c;它是一種直觀的能夠被電腦識別的數據序列化格式&#xff0c;是一種可讀性高且容易被人類閱讀的腳本語言YAML語言的本質是一種通用的數據串行化格式適用場景 可以直接序列化為數組、字典解析成本低專門寫配置文…

審批流程系統設計與實現:狀態驅動、靈活擴展的企業級解決方案

審批流程系統設計與實現&#xff1a;狀態驅動、靈活擴展的企業級解決方案 本文基于實際企業級審批系統源碼&#xff0c;深入解析如何設計高擴展性、強一致性的審批流程引擎&#xff0c;涵蓋狀態機設計、多租戶隔離、文件服務集成等核心實現。 1. 系統設計概覽 審批系統的核心架…

汽車免拆診斷案例 | 2010款奧迪A4L車行駛中發動機偶爾自動熄火

故障現象 一輛2010款奧迪A4L車&#xff0c;搭載CDZ發動機 &#xff0c;累計行駛里程約為18.2萬km。該車行駛中發動機偶爾自動熄火&#xff0c;有時熄火后能夠立即重新起動著機&#xff0c;有時需要等待一會兒才能重新起動著機&#xff0c;故障頻率較低。因該故障在其他維修廠陸…

Liam ERD:自動生成美觀的交互式實體關系圖

Liam ERD 是一個可以快速生成美觀且具有交互性的數據庫實體關系圖&#xff08;ERD&#xff09;的工具&#xff0c;可以幫助用戶實現復雜數據庫結構的可視化。 Liam ERD 是一個免費開源的項目&#xff0c;代碼托管在 GitHub&#xff1a; https://github.com/liam-hq/liam 功能…

網絡協議序列化工具Protobuf

目錄前言一、下載注意二、解壓安裝三、Protobuf的使用1、創建.proto文件2、利用protoc編譯.proto文件前言 Protocol Buffers是Google的?種語??關、平臺?關、可擴展的序列化結構數據的?法&#xff0c;它可?于&#xff08;數據&#xff09;通信協議、數據存儲等。 Protoco…

從表單校驗到API網關:全鏈路輸入安全防護指南

從表單校驗到 API 網關:全鏈路輸入安全防護指南 在軟件系統的安全防御體系中,輸入安全是第一道防線,而這道防線的堅固程度直接決定了系統抵御外部攻擊的能力。從用戶在瀏覽器中填寫表單的那一刻起,到數據經過 API 網關流轉至后端服務,每一個環節都可能成為輸入攻擊的突破…

Flask vs Django:微框架與一站式對決

Flask 簡介 1、簡介 Flask誕生于2010年&#xff0c;是Armin ronacher用Python語言基于Werkzeug工具箱編寫的輕量級Web開發框架&#xff0c;又稱之為微框架。 "微"的含義&#xff1a;Flask旨在保持核心簡潔&#xff0c;本身相當于內核&#xff0c;其他功能需通過擴展…

真實業務場景:mysql慢查詢優化(從17秒的查詢優化到700毫秒)

慢查詢業務場景:原先在我們系統中要統計一些人員的單位 部門信息的數據情況&#xff0c;比如總的男女人數&#xff0c;每個單位下的男女人數等等&#xff0c;然后原來的sql是這樣寫的 根據一個單位的id 然后對一張表做出多個子查詢進行查詢&#xff0c;這時候統計記錄 由于加載…

遠程影音訪問:通過 cpolar 內網穿透服務使用 LibreTV

文章目錄前言【視頻教程】1.關于LibreTV2.docker部署LibreTV3.簡單使用LibreTV4.安裝cpolar內網穿透5.配置ward公網地址6.配置固定公網地址總結LibreTV 與 cpolar 的協同應用&#xff0c;為用戶打造了一條通往高清觀影自由的便捷之路。通過這一方案&#xff0c;用戶不僅擺脫了商…

Apache ECharts 6 核心技術解密 – Vue3企業級可視化實戰指南

簡介 ECharts 是百度開源的一個使用 JavaScript 實現的開源可視化庫&#xff0c;它能夠生動、可交互地展示數據。在 Vue3 項目中集成 ECharts 可以讓你的項目更加直觀和動態地呈現數據信息。 核心優勢 特性SVG渲染器Canvas渲染器縮放保真度★★★★★★★☆☆☆動態交互性能…