You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

关于获取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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 01:33:04