1. 项目概述为什么future::get()的异常处理是C高性能系统的“阿克琉斯之踵”如果你正在用C构建一个需要处理高并发、低延迟请求的后台服务或者一个需要大量并行计算的科学模拟程序那么std::future和std::async绝对是你工具箱里的常客。它们让异步编程变得前所未有的简单几行代码就能把任务丢到后台主线程继续欢快地跑着等需要结果时一个future.get()数据就“嗖”地一下回来了。这感觉就像点了个外卖然后该干嘛干嘛饭到了自然通知你。但问题就出在这个“等外卖”的过程里。绝大多数教程和入门代码都只展示了最理想的情况任务成功执行get()顺利返回结果。然而在真实的生产环境中尤其是在高性能系统里后台任务“送餐失败”才是常态——可能是计算资源耗尽、访问了非法内存、依赖的服务超时或者干脆遇到了一个未处理的逻辑异常。这时future.get()就不再是温和的数据搬运工而会变成一个“异常炸弹”的引爆器将后台线程的崩溃直接“抛”到你的主调用线程脸上。如果处理不当轻则程序崩溃用户体验归零重则异常在调用链中 silent propagation静默传播导致状态不一致、资源泄漏甚至引发更诡异的系统性故障。我见过太多团队在性能压测时系统跑得飞快一上线就各种离奇崩溃追查到最后往往就是某个角落里的future.get()吞掉了异常或者异常处理逻辑根本就没写。这绝不是危言耸听异步任务中的异常是“非局部”的它的影响范围和排查难度远大于同步代码。因此掌握future::get()的异常处理不是“锦上添花”的可选项而是构建健壮、可靠的高性能C系统的必修课。今天我们就深入探讨三种超越try-catch的基础用法能真正应用于复杂生产环境的高级异常处理模式。2. 核心需求解析从“不崩溃”到“可观测、可恢复”在深入模式之前我们必须先厘清在处理future::get()异常时我们到底在解决什么问题绝不仅仅是“不让程序崩溃”那么简单。对于一个高性能系统异常处理机制需要满足以下几个层次的需求第一层基础生存Survival。这是底线即程序不能因为一个后台任务的失败而整体垮掉。简单的try-catch包裹future.get()就能达到这一层但这只是开始。第二层状态可观测Observability。当异常发生时系统必须能清晰地知道是哪个任务失败了失败的原因是什么异常类型和消息失败发生在什么时候这些信息对于监控、告警和事后排查至关重要。原始的std::exception_ptr虽然能捕获异常但信息不直观不利于日志记录。第三层资源与上下文安全Safety。异常发生后必须确保不会发生资源泄漏如内存、文件句柄、网络连接并且共享状态不会被破坏。特别是在使用std::shared_future或多个线程等待同一个结果时异常处理需要保证线程安全。第四层流程可恢复/可降级Resilience。这是高级需求。对于某些非关键任务系统可能允许失败并启用备用逻辑如返回默认值、重试、或跳过该步骤。异常处理机制需要为这种决策提供支持。第五层性能与开销Performance。异常处理本身不能成为性能瓶颈。频繁的异常抛出和捕获尤其是基于表的异常实现是有开销的。我们的模式需要在健壮性和性能之间取得平衡。传统的try { auto result fut.get(); } catch (const std::exception e) { std::cerr e.what(); }只解决了第一层并且信息输出也很原始。接下来介绍的三种模式正是为了系统性地满足上述更高层次的需求而设计的。3. 模式一结果封装器Result Monad模式——将异常转化为可编程的状态第一种模式我称之为“结果封装器”模式灵感来源于函数式编程中的Result或EitherMonad。其核心思想是避免让异常“抛出来”而是将它作为返回值的一部分封装在一个容器类型里。这样异步操作的结果就变成了一个明确的、可枚举的状态要么是成功的值要么是错误信息。3.1 设计与实现我们首先定义一个模板类ResultT它可以容纳一个类型为T的成功值或者一个std::exception_ptr。#include exception #include memory #include type_traits #include variant // C17 或使用手写的类型安全联合体 templatetypename T class Result { public: // 成功构造函数 Result(T value) : data_(std::move(value)) {} // 失败构造函数 Result(std::exception_ptr eptr) : data_(std::move(eptr)) {} // 检查是否成功 bool has_value() const { return std::holds_alternativeT(data_); } // 检查是否失败 bool has_error() const { return std::holds_alternativestd::exception_ptr(data_); } // 获取值仅在成功时调用 T value() { if (!has_value()) { std::rethrow_exception(std::getstd::exception_ptr(data_)); } return std::getT(data_); } const T value() const { if (!has_value()) { std::rethrow_exception(std::getstd::exception_ptr(data_)); } return std::getT(data_); } // 获取异常指针仅在失败时调用 std::exception_ptr error() const { if (!has_error()) { throw std::logic_error(No error present in Result); } return std::getstd::exception_ptr(data_); } // 便捷的取值或提供默认值 T value_or(T default_val) const { return has_value() ? std::getT(data_) : default_val; } private: std::variantT, std::exception_ptr data_; };有了这个Result容器我们就可以改造异步任务的调用方式。核心工具是一个包装函数templatetypename Func, typename... Args auto async_with_result(Func func, Args... args) - std::futureResultstd::invoke_result_tFunc, Args... { using ReturnType std::invoke_result_tFunc, Args...; return std::async(std::launch::async, [func std::forwardFunc(func), ...args std::forwardArgs(args)]() mutable - ResultReturnType { try { // 尝试执行任务成功则封装值 if constexpr (std::is_void_vReturnType) { std::invoke(std::forwardFunc(func), std::forwardArgs(args)...); return ResultReturnType(); // 可能需要为void特化Result } else { return ResultReturnType(std::invoke(std::forwardFunc(func), std::forwardArgs(args)...)); } } catch (...) { // 捕获任何异常封装为失败结果 return ResultReturnType(std::current_exception()); } }); }3.2 使用方式与优势使用时代码会变得非常声明式和安全auto future_result async_with_result([]() - int { // 模拟可能失败的任务 if (rand() % 2) throw std::runtime_error(Random task failed!); return 42; }); // ... 主线程做其他事情 ... auto result future_result.get(); // 这里绝对不会抛出异常 if (result.has_value()) { std::cout Task succeeded with value: result.value() std::endl; // 安全地使用 result.value() } else { std::cerr Task failed. std::endl; try { std::rethrow_exception(result.error()); } catch (const std::exception e) { std::cerr Error details: e.what() std::endl; // 这里可以记录更结构化的日志包含错误类型、时间、任务ID等 } // 或者使用降级策略 int fallback_value result.value_or(-1); }这个模式的核心优势在于调用栈安全future.get()不再抛出异常传播路径被显式中断在后台线程内主线程控制流保持清晰。状态显式化成功/失败变成了一个可以if-else判断的布尔状态逻辑更直观。错误信息可携带std::exception_ptr可以跨线程传递保留了原始的异常类型和消息便于后续详细分析。易于组合可以方便地实现链式调用或组合多个可能失败的操作类似and_then,or_else语义。实操心得在实现Result类时我强烈建议使用std::variantC17而非手写的联合体加标签它提供了完美的类型安全和生命周期管理。对于C11/14可以借鉴std::experimental::expected的实现思路。另外可以为Result添加更多的功能性方法如map、bind使其真正成为一个Monad极大提升异步错误处理的表达能力。4. 模式二回调与Promise风格——将异常处理权交给调用者第二种模式更接近JavaScript Promise或许多网络库的Completion Handler风格。其核心思想是不通过get()同步等待结果而是预先注册好成功和失败的回调函数。当异步任务完成无论成功失败时自动调用相应的回调。这彻底避免了阻塞等待是高性能、高并发场景下的首选。4.1 设计与实现我们可以构建一个简单的PromiseT和FutureT对注意这不是std::promise而是更高级的抽象支持then和on_error链式调用。#include functional #include memory #include exception templatetypename T class Promise; templatetypename T class Future { public: using SuccessCallback std::functionvoid(T); using ErrorCallback std::functionvoid(std::exception_ptr); Future() default; // 注册成功回调 Future then(SuccessCallback cb) { success_cb_ std::move(cb); try_invoke(); return *this; } // 注册失败回调 Future on_error(ErrorCallback cb) { error_cb_ std::move(cb); try_invoke(); return *this; } private: friend class PromiseT; Future(std::shared_ptrPromiseT promise) : promise_(std::move(promise)) {} void try_invoke() { auto promise promise_.lock(); if (!promise) return; if (promise-is_ready()) { if (promise-has_value() success_cb_) { success_cb_(promise-get_value()); } else if (promise-has_error() error_cb_) { error_cb_(promise-get_error()); } // 调用后可以清理防止重复调用 success_cb_ nullptr; error_cb_ nullptr; } } std::weak_ptrPromiseT promise_; SuccessCallback success_cb_; ErrorCallback error_cb_; }; templatetypename T class Promise { public: Promise() : state_(State::Pending) {} // 设置成功值 void set_value(T value) { std::lock_guardstd::mutex lock(mtx_); if (state_ ! State::Pending) return; value_ std::move(value); state_ State::HasValue; notify_future(); } // 设置异常 void set_exception(std::exception_ptr eptr) { std::lock_guardstd::mutex lock(mtx_); if (state_ ! State::Pending) return; error_ std::move(eptr); state_ State::HasError; notify_future(); } // 获取关联的Future FutureT get_future() { return FutureT(shared_from_this()); } bool is_ready() const { return state_ ! State::Pending; } bool has_value() const { return state_ State::HasValue; } bool has_error() const { return state_ State::HasError; } T get_value() const { return value_; } std::exception_ptr get_error() const { return error_; } private: void notify_future() { // 在实际实现中这里可能需要通知所有等待的Future对象。 // 为了简化我们依赖Future在注册回调和检查状态时主动拉取。 } enum class State { Pending, HasValue, HasError }; mutable std::mutex mtx_; State state_; T value_{}; std::exception_ptr error_; // 注意Promise需要继承自 std::enable_shared_from_this };然后我们提供一个启动异步任务的函数它返回一个Futuretemplatetypename Func, typename... Args Futurestd::invoke_result_tFunc, Args... async_promise(Func func, Args... args) { using ReturnType std::invoke_result_tFunc, Args...; auto promise std::make_sharedPromiseReturnType(); auto future promise-get_future(); std::thread([promise, func std::forwardFunc(func), ...args std::forwardArgs(args)]() mutable { try { if constexpr (std::is_void_vReturnType) { std::invoke(std::forwardFunc(func), std::forwardArgs(args)...); promise-set_value(); // 需要为void特化set_value } else { promise-set_value(std::invoke(std::forwardFunc(func), std::forwardArgs(args)...)); } } catch (...) { promise-set_exception(std::current_exception()); } }).detach(); // 实际生产环境请使用线程池 return future; }4.2 使用方式与优势使用起来非常流畅完全异步auto future async_promise([]() - std::string { std::this_thread::sleep_for(std::chrono::milliseconds(100)); if (rand() % 3 0) { throw std::runtime_error(Network timeout simulated); } return Data fetched successfully; }); future .then([](const std::string data) { std::cout [SUCCESS] Received: data std::endl; // 这里可以继续发起新的异步操作返回另一个Future实现链式调用 }) .on_error([](std::exception_ptr eptr) { try { std::rethrow_exception(eptr); } catch (const std::runtime_error e) { std::cerr [ERROR] Runtime error: e.what() std::endl; // 执行错误恢复逻辑例如重试、使用缓存、上报监控等 } catch (...) { std::cerr [ERROR] Unknown exception std::endl; } }); // 主线程立即返回不会阻塞 std::cout Main thread continues without blocking... std::endl;这个模式的核心优势在于非阻塞彻底消除了get()带来的线程阻塞极大提高了并发能力和响应速度。关注点分离业务逻辑成功处理和错误处理逻辑被清晰地分离到不同的回调函数中代码结构更清晰。易于链式与组合通过返回Future对象可以轻松实现“任务A完成后触发任务BB失败后触发降级C”这样的复杂异步工作流。资源控制回调的执行上下文在哪个线程执行可以由线程池或特定的执行器Executor来控制提供了更灵活的调度能力。注意事项实现一个生产级别的Promise/Future库需要考虑很多细节如线程安全、回调的内存管理避免循环引用、执行器的集成、超时控制等。上述示例是一个高度简化的教学模型。在实际项目中我强烈建议直接使用成熟的库如Facebook的folly::Future、Boost.Thread中的boost::future支持.then或C23标准中的std::future扩展支持continuations。自己造轮子容易陷入并发陷阱。5. 模式三结构化异常日志与监控集成模式第三种模式侧重于运维和可观测性。在高性能分布式系统中一个异常的价值不仅在于被处理更在于被记录、被分析、被预警。这种模式的核心思想是将future::get()可能抛出的异常自动转化为结构化的、富含上下文信息的日志事件并无缝集成到系统的监控告警体系中。5.1 设计与实现我们创建一个LoggedFutureT包装器它在内部包裹一个std::futureT并重载get()方法。在get()被调用时它除了返回结果或抛出异常还会自动进行日志记录。#include future #include chrono #include sstream #include iomanip // 假设有一个全局或注入的日志接口 class Logger { public: enum class Level { Debug, Info, Warn, Error }; virtual void log(Level lvl, const std::string message, const std::string context ) 0; virtual ~Logger() default; }; templatetypename T class LoggedFuture { public: LoggedFuture(std::futureT fut, std::string task_name, std::shared_ptrLogger logger) : future_(std::move(fut)), task_name_(std::move(task_name)), logger_(std::move(logger)), start_time_(std::chrono::steady_clock::now()) {} // 核心重载 get() 方法 T get() { auto end_time std::chrono::steady_clock::now(); auto duration std::chrono::duration_caststd::chrono::milliseconds(end_time - start_time_); try { T result future_.get(); // 调用原始的get可能抛出 // 成功日志 if (logger_) { std::ostringstream oss; oss Async task completed successfully. [Task: task_name_ , Duration: duration.count() ms]; logger_-log(Logger::Level::Info, oss.str()); } return result; } catch (const std::exception e) { // 失败日志包含异常详情和上下文 if (logger_) { std::ostringstream oss; oss Async task FAILED with exception. [Task: task_name_ , Duration: duration.count() ms, Exception: typeid(e).name() - e.what() ]; logger_-log(Logger::Level::Error, oss.str()); // 这里可以附加更多上下文如线程ID、时间戳、相关请求ID等 } // 重新抛出异常保证原有语义不变 throw; } catch (...) { if (logger_) { std::ostringstream oss; oss Async task FAILED with unknown exception. [Task: task_name_ , Duration: duration.count() ms]; logger_-log(Logger::Level::Error, oss.str()); } throw; } } // 也可以提供其他future接口如wait_for, valid等转发给内部的future_ // ... private: std::futureT future_; std::string task_name_; // 任务标识便于追踪 std::shared_ptrLogger logger_; std::chrono::steady_clock::time_point start_time_; };同时我们提供一个创建LoggedFuture的辅助函数templatetypename Func, typename... Args auto async_with_logging(Func func, Args... args, std::string task_name, std::shared_ptrLogger logger) - LoggedFuturestd::invoke_result_tFunc, Args... { using ReturnType std::invoke_result_tFunc, Args...; auto std_future std::async(std::launch::async, std::forwardFunc(func), std::forwardArgs(args)...); return LoggedFutureReturnType(std::move(std_future), std::move(task_name), std::move(logger)); }5.2 使用方式与集成监控// 假设有一个具体的Logger实现 class SpdlogLogger : public Logger { /* ... 实现log方法输出到文件或网络 ... */ }; auto logger std::make_sharedSpdlogLogger(); // 使用带日志的异步调用 auto logged_future async_with_logging( []() - int { // 模拟一个复杂任务 std::this_thread::sleep_for(50ms); if (some_condition()) throw std::logic_error(Invalid state detected); return compute_intensive_result(); }, BackgroundDataProcessor, // 给任务起个有意义的名字 logger ); // 在需要结果的地方调用get()日志会自动记录 try { int processed_data logged_future.get(); use_data(processed_data); } catch (const std::logic_error e) { // 本地处理逻辑错误 handle_logic_error(e); } catch (...) { // 处理其他未知错误 }这个模式的核心优势在于无侵入性业务代码几乎不需要修改只需换一个Future包装类型和创建函数。丰富的上下文日志中自动包含了任务名、执行耗时、异常类型和消息这些信息对于定位问题至关重要。统一出口所有异步任务的异常日志格式统一便于后续的日志聚合、分析和设置告警规则例如同一任务在1分钟内失败超过5次则触发PagerDuty告警。性能监控自动记录的任务耗时是性能分析和容量规划的重要指标。实操心得在实际项目中不要只记录到本地文件。应该将Logger抽象化使其后端可以对接ELKElasticsearch, Logstash, Kibana、PrometheusGrafana、或分布式追踪系统如Jaeger。这样一个异步任务的失败不仅能留下日志还能在监控大盘上产生一个红色的指标点在追踪视图上显示一个错误的Span。这才是现代可观测性系统的做法。此外task_name的设计很有讲究最好能包含业务模块、操作类型和唯一标识符如UserService-UpdateProfile-RequestID:12345方便进行聚合查询。6. 三种模式的对比与选型指南上面介绍了三种各具特色的高级模式它们并非互斥而是适用于不同的场景。为了帮助你做出选择我整理了一个详细的对比表格特性维度模式一结果封装器 (Result Monad)模式二回调与Promise风格模式三结构化日志与监控核心思想将异常转化为返回值的一部分使错误状态显式化。通过注册回调处理完成事件实现完全非阻塞。在异常传播的关键点自动注入日志和监控点。调用方式同步或异步等待后检查Result对象的状态。纯异步通过.then()和.on_error()链式注册回调。同步等待get()但行为被增强。线程阻塞future.get()不抛异常但调用仍会阻塞直到任务完成。完全不阻塞主线程立即返回。get()会阻塞与标准future一致。错误处理位置在调用get()之后通过检查Result状态来处理。在预先注册的on_error回调函数中处理。在get()调用点通过catch处理同时触发日志。代码风格函数式强调值和状态的变换。响应式/事件驱动流程由回调定义。面向切面AOP对原有代码侵入小。可观测性一般需要手动从Result中提取错误信息并记录。一般需要在错误回调中手动添加日志。优秀自动、结构化地记录异常和上下文。组合复杂度中等需要定义Result类型和相关组合子。高需要实现或依赖完整的Promise/Future库。低主要是包装和转发。适用场景1. 需要明确处理成功/失败两种状态的同步/异步接口。2. 函数式风格浓厚的代码库。3. 错误需要作为业务逻辑的一部分进行传递和转换。1. 高性能服务器要求绝对的非阻塞。2. 复杂的异步工作流多个任务依赖、并行、竞速。3. UI或游戏主循环不能有任何阻塞。1. 所有需要强化监控和可观测性的生产系统。2. 遗留代码改造希望增加异常追踪但改动最小。3. 作为前两种模式的补充增强其可观测性。推荐使用时机当你希望错误处理逻辑像处理普通数据一样清晰并且不介意轻微的阻塞时。当系统吞吐量和响应延迟是首要指标且你愿意接受更复杂的异步编程模型时。几乎任何时候可观测性是生产系统的生命线此模式应作为基础设施。我的个人选型建议是对于全新的高性能C服务我倾向于模式二Promise风格 模式三日志监控的组合。使用一个成熟的Future库如folly::Future来处理所有异步流程和错误同时在这个库的底层或适配层集成模式三的日志记录能力。这样既能获得极致的性能和非阻塞的优势又能保证系统的可观测性。对于改造现有大量使用std::async和future.get()的代码或者在一些对性能要求不是极端苛刻、但希望大幅提升健壮性的模块中模式一Result封装是一个折中且有效的选择它改动相对较小又能带来状态显式化的好处。7. 进阶技巧与性能陷阱规避掌握了核心模式我们还需要关注一些进阶细节和容易踩坑的地方这些往往是区分普通程序员和资深架构师的关键。7.1 异常类型与std::future_error除了你业务代码抛出的自定义异常future::get()本身还可能抛出std::future_error。这通常发生在future状态无效时例如对同一个future对象多次调用get()。future关联的promise在设置值/异常前被销毁。future是通过std::async启动的延迟任务std::launch::deferred但在其他线程调用了get()。避坑指南永远假设future.get()可能抛出std::future_error。在你的最外层捕获处理中至少要区分业务异常和系统异常try { auto result my_future.get(); } catch (const std::future_error fe) { // 处理future状态错误这通常是编程错误或资源生命周期问题 std::cerr Future error: fe.what() Code: fe.code() std::endl; } catch (const MyBusinessException e) { // 处理业务逻辑异常 handle_business_error(e); } catch (const std::exception e) { // 处理标准库异常 log_generic_error(e); } catch (...) { // 处理未知异常 log_unknown_error(); }7.2 超时控制不要让一个异常任务拖垮整个系统这是高性能系统设计中的致命陷阱。一个后台任务可能因为死锁、死循环或外部服务无限期挂起而永远无法完成。如果你在主线程或关键线程中同步等待它的future.get()整个线程就会被无限期阻塞。解决方案是使用std::future::wait_for或std::future::wait_untilauto future std::async(std::launch::async, some_possibly_hanging_task); // 设置一个合理的超时时间例如500毫秒 auto status future.wait_for(std::chrono::milliseconds(500)); if (status std::future_status::ready) { try { auto result future.get(); // 处理结果 } catch (...) { // 处理任务执行中抛出的异常 } } else if (status std::future_status::timeout) { // 超时处理记录告警执行降级逻辑甚至可以考虑放弃这个future有风险 std::cerr Warning: Async task timed out. Initiating fallback. std::endl; // 重要超时后future对象仍然有效任务仍在后台运行。 // 需要设计策略来处理这个“僵尸”任务比如全局任务管理器可以强制中断它。 } else { // status std::future_status::deferred // 延迟任务通常不会在async中遇到除非指定了std::launch::deferred }性能陷阱警告wait_for超时后后台线程和任务并没有停止它还在继续消耗资源。对于真正的“失控”任务C标准库没有提供安全的线程中断机制。一个常见的实践是将任务包装在可以定期检查“取消标志”的循环中超时后设置该标志。或者使用第三方库如Boost.Thread提供的可中断线程。7.3 线程池与资源管理不要为每个小任务都std::async一个线程。线程创建和销毁的开销巨大无限制的线程数会耗尽系统资源。务必使用线程池。// 简单的线程池使用示例概念性代码 class ThreadPool { public: templatetypename F, typename... Args auto enqueue(F f, Args... args) - std::futuredecltype(f(args...)) { using return_type decltype(f(args...)); auto task std::make_sharedstd::packaged_taskreturn_type()( std::bind(std::forwardF(f), std::forwardArgs(args)...) ); std::futurereturn_type res task-get_future(); { std::unique_lockstd::mutex lock(queue_mutex_); tasks_.emplace([task](){ (*task)(); }); } condition_.notify_one(); return res; // 返回 future可以应用上述任何一种异常处理模式 } // ... 其他实现工作线程循环等 }; ThreadPool pool(4); // 4个工作线程 auto future pool.enqueue(heavy_computation); // 对返回的future应用模式一、二或三将线程池返回的future与我们讨论的异常处理模式结合是构建稳健异步系统的基石。7.4 异常安全与资源泄漏确保你的异步任务函数本身是异常安全的。如果任务在持有锁、打开文件或分配了内存时抛出异常必须确保这些资源能被正确释放。RAIIResource Acquisition Is Initialization是你的最佳伙伴。auto future std::async([]() { std::unique_ptrResource res acquire_resource(); // RAII管理 std::lock_guardstd::mutex lock(some_mutex); // RAII管理锁 // 即使这里抛出异常res和lock也会被正确释放 return process(*res); });8. 实战构建一个简单的异步HTTP客户端异常处理框架让我们综合运用以上知识设计一个简易的、健壮的异步HTTP客户端模块。它需要1非阻塞调用2完善的错误处理网络错误、超时、解析错误3结构化日志。我们将采用模式二Promise风格作为主要异步模型并集成模式三日志监控。#include string #include memory #include functional // 1. 定义结果和错误类型 struct HttpResponse { int status_code; std::string body; // ... headers等 }; enum class HttpError { Timeout, NetworkFailure, InvalidResponse, // ... }; class HttpException : public std::runtime_error { public: HttpException(HttpError err, const std::string msg) : std::runtime_error(msg), error_code_(err) {} HttpError error() const { return error_code_; } private: HttpError error_code_; }; // 2. 使用一个假设的Promise库此处用伪代码表示接口 using HttpFuture SomePromiseLibrary::FutureHttpResponse; // 3. 带日志和监控的HTTP客户端 class AsyncHttpClient { public: AsyncHttpClient(std::shared_ptrLogger logger, std::shared_ptrThreadPool pool) : logger_(logger), pool_(pool) {} HttpFuture Get(const std::string url, std::chrono::milliseconds timeout) { auto promise std::make_sharedSomePromiseLibrary::PromiseHttpResponse(); auto future promise-get_future(); // 记录任务开始 auto task_id generate_task_id(); auto start std::chrono::steady_clock::now(); if(logger_) logger_-log(Logger::Level::Info, HTTP_GET_START, task_id | url); // 提交到线程池执行IO密集型操作 pool_-enqueue([promise, url, timeout, task_id, start, logger logger_]() { try { // 模拟HTTP请求实际使用libcurl, boost.asio等 std::this_thread::sleep_for(std::chrono::milliseconds(100)); // 模拟网络延迟 // 模拟随机失败 if (rand() % 10 0) { throw HttpException(HttpError::Timeout, Request to url timed out); } if (rand() % 10 1) { throw HttpException(HttpError::NetworkFailure, Connection refused for url); } // 模拟成功响应 HttpResponse resp{200, {\data\: \ok\}}; promise-set_value(resp); // 记录成功日志 auto end std::chrono::steady_clock::now(); auto dur std::chrono::duration_caststd::chrono::milliseconds(end - start); if(logger) logger-log(Logger::Level::Info, HTTP_GET_SUCCESS, task_id | url | std::to_string(dur.count()) ms); } catch (const HttpException e) { // 业务已知异常 promise-set_exception(std::make_exception_ptr(e)); auto end std::chrono::steady_clock::now(); auto dur std::chrono::duration_caststd::chrono::milliseconds(end - start); if(logger) logger-log(Logger::Level::Error, HTTP_GET_FAILURE, task_id | url | std::to_string(dur.count()) ms| e.what()); } catch (...) { // 未知异常 promise-set_exception(std::current_exception()); if(logger) logger-log(Logger::Level::Error, HTTP_GET_UNKNOWN_ERROR, task_id | url); } }); return future; } private: std::string generate_task_id() { /* 生成唯一ID */ return req_ std::to_string(req_counter_); } std::shared_ptrLogger logger_; std::shared_ptrThreadPool pool_; std::atomicint req_counter_{0}; }; // 4. 使用示例 int main() { auto logger std::make_sharedSpdlogLogger(); auto pool std::make_sharedThreadPool(4); AsyncHttpClient client(logger, pool); auto future client.Get(https://api.example.com/data, std::chrono::seconds(5)); future .then([](const HttpResponse resp) { std::cout Got response: resp.status_code , body: resp.body std::endl; // 解析JSON继续处理... }) .on_error([](std::exception_ptr eptr) { try { std::rethrow_exception(eptr); } catch (const HttpException e) { std::cerr HTTP request failed with code static_castint(e.error()) : e.what() std::endl; // 根据错误类型执行降级如使用缓存、返回默认值、重试等 switch(e.error()) { case HttpError::Timeout: // 重试逻辑 break; case HttpError::NetworkFailure: // 使用本地缓存 break; // ... } } catch (const std::exception e) { std::cerr Unexpected error: e.what() std::endl; } }); // 主线程继续处理其他事情 std::this_thread::sleep_for(std::chrono::seconds(2)); return 0; }这个框架展示了如何将高级异常处理模式、资源管理线程池、可观测性结构化日志结合在一个实际场景中。它具备了生产级代码的雏形非阻塞、错误分类处理、全链路追踪和降级策略。