关于获取loader::load_async返回类型的技术问询及优化建议
问题解答
1. 这种做法是否合理?
用std::map存储异步任务的std::future,并在系统tick中轮询检查任务完成状态的思路是合理的,但需要注意几个关键点:
std::future是一次性的:调用get()后状态会变为无效,无法再次检查或获取结果,若需多次检查状态,建议改用std::shared_future。- 线程安全:如果任务提交与tick检查在不同线程执行,必须对
std::map的访问加锁(比如std::mutex配合std::lock_guard),避免数据竞争。 - 资源管理:任务完成后要及时从map中移除,避免内存泄漏。
2. 如何获取loader::load_async的返回类型?
有两种常用方式:
方式一:用decltype自动推导
直接通过decltype推导load_async的返回类型,适合返回类型不确定的场景:
void use() { loader loader_; // 推导load_async<data>的返回类型 using RequestFuture = decltype(loader_.load_async<data>(std::string("key"), true)); std::map<std::string, RequestFuture> requests; std::string key = "key"; requests[key] = loader_.load_async<data>(key, true); }
注意:原代码中loader_.load_async<data>("key", true)存在引用绑定临时变量的问题,需修正为传入左值(如上面的std::string key),或把load_async的第一个参数改为const std::string&。
方式二:直接指定返回类型
如果明确知道load_async中lambda的返回类型(比如data),可以直接写std::future<data>:
void use() { loader loader_; std::map<std::string, std::future<data>> requests; std::string key = "key"; requests[key] = loader_.load_async<data>(key, true); }
3. 更合适的解决方案?
根据场景需求,有几种更优的方案可选:
方案一:回调模式(替代轮询)
不需要主动tick轮询,而是在任务完成时触发回调函数,更高效且避免轮询开销:
// 修改loader的load_async,支持回调 class loader { thread_pool pool_; public: template<typename T, typename... Ts, typename Callback> void load_async(const std::string& key, Ts... args, Callback&& callback) { pool_.enqueue([key, args..., callback = std::forward<Callback>(callback)]() { // 执行加载逻辑,生成T类型结果 data result(key, args...); // 任务完成后触发回调 callback(key, std::move(result)); }); } }; // user中使用回调 class user { std::unordered_map<std::string, data> cached_data_; std::mutex cache_mutex_; public: void use() { loader loader_; std::string key = "key"; loader_.load_async<data>(key, true, [this](const std::string& k, data&& result) { std::lock_guard<std::mutex> lock(cache_mutex_); cached_data_[k] = std::move(result); // 添加任务完成后的其他逻辑 }); } };
方案二:封装任务跟踪类
把任务管理逻辑封装到独立类中,提高代码复用性和可维护性:
class RequestTracker { private: std::mutex mutex_; std::unordered_map<std::string, std::shared_future<data>> requests_; std::unordered_map<std::string, std::function<void(data&&)>> callbacks_; public: void add_request(const std::string& key, std::shared_future<data> future, std::function<void(data&&)> callback) { std::lock_guard<std::mutex> lock(mutex_); requests_[key] = std::move(future); callbacks_[key] = std::move(callback); } void tick() { std::lock_guard<std::mutex> lock(mutex_); for (auto it = requests_.begin(); it != requests_.end(); ) { auto status = it->second.wait_for(std::chrono::seconds(0)); if (status == std::future_status::ready) { // 触发回调处理结果 auto result = it->second.get(); callbacks_[it->first](std::move(result)); // 清理资源 callbacks_.erase(it->first); it = requests_.erase(it); } else { ++it; } } } }; // user中使用跟踪类 class user { RequestTracker tracker_; public: void use() { loader loader_; std::string key = "key"; auto future = loader_.load_async<data>(key, true); tracker_.add_request(key, std::shared_future<data>(future), [this](data&& result) { // 处理完成的任务 }); } // 在系统tick中调用 void on_tick() { tracker_.tick(); } };
方案三:使用并发容器
如果项目允许,可以用线程安全的并发容器(比如C++20的std::flat_hash_map配合std::shared_mutex,或第三方库如Abseil的absl::flat_hash_map)替代普通std::map,简化线程安全逻辑。
内容的提问来源于stack exchange,提问作者atg
相关产品推荐
相关产品推荐

