C++std::async 简单研究

它是 c++ 标准库提供的 API,用于异步(创建单独的线程)或同步(正常调用函数)执行任务(作为参数传递)。 这取决于启动策略。

参数

  • f 要调用的可调用 (Callable) 对象
  • args 传递给 f 的参数
  • policy 位掩码值,每个单独位控制允许的执行方法
解释
std::launch::async启用异步求值,运行新线程,以异步执行任务
std::launch::deferred启用惰性求值,在调用线程上执行任务(惰性求值)。在对 future 调用 get wait 的时候,才进行执行。如果什么都没有发生,那么执行函数就没有运行。
launch::async|launch::deferred这是自动的,该函数在特定点自动选择策略。 这取决于系统以及库实现,这通常针对系统中当前的并发可用性进行优化

注:不使用策略参数调用 async(f, 1, 2, 3) ,我们将会选择都是用的策略。 async 的实现可以自由的选择策略。这也就意味着,我们不能确定任务会执行在一个新的线程上,还是执行在当前线程上。

启动策略

启动策略是 std::async API 的一部分,它作为第一个参数传递。 共有三种启动策略 :

  • std::launch::async
  • std::launch::deferred
  • 默认策略(std::launch::async | std::launch::deferred)

std::launch::async

它将函数作为 单独的线程 启动,如果资源不可用,那么我们将得到异常(std::system_error 错误 std::resource::unavailable_try_again)。
例子:

//创建单独的线程
std::future<int>result1=std::async(std::launch::async,AddThread,3,3);

std::launch::deferred

它将函数作为 同步调用 当调用 futureget() wait() 时 启动。 如果有人使用延迟策略启动异步并且不调用 futureget() wait(),那么函数将永远不会启动 。
例子:

//Using std::launch::deferred policy, no separate thread.
auto result2 = std::async(std::launch::deferred, MulThread, 3, 3);

默认策略

它是上述两种策略的组合或留空(请查看下面的示例),它以异步方式(创建单独的线程)或同步方式(正常调用函数)启动函数,它取决于库,库将选择基于上述策略之一关于资源的可用性。
例子:

//Using Default Policy
//Both below function signature are same, we can use anyone.
std::async(std::launch::async|std::launch::deferred, AddThread, 6, 6);
or
std::async(AddThread, 6, 6);

综合示例

  • 示例1:
#include <future>
#include <iostream>
// 检查它是否是质数
// 参数是必须检查的数字
bool fnprime(int num) {
    std::cout << "处理开始。。。请等待。。。\n";
    int i = 1;

    while (1) {
        std::cout << "处理数值" << num << "  " << i << std::endl;
        i++;
        if (i > 100) {
            break;
        }
    }
    for (; i < num + 100; ++i) {
        // 如果 mod 为0,返回 false,否则返回0

        std::cout << "处理数值" << num << "  " << i << std::endl;
    }
    return true;
}
// main method
int main() {
    int num = 20;
    // 异步调用函数 fnprime ()检查数字是否为质数:
    std::future<bool> fobj = std::async(std::launch::async, [&]() -> bool {
        std::cout << "处理开始。。。请等待。。。\n";
        int i = 1;

        while (1) {
            std::cout << "处理数值" << num << "  " << i << std::endl;
            i++;
            if (i > 100) {
                break;
            }
        }
        for (; i < num + 100; ++i) {
            // 如果 mod 为0,返回 false,否则返回0

            std::cout << "处理数值" << num << "  " << i << std::endl;
        }
        return true;
    });
    // 打印该行以显示状态
    std::cout << "检查数字4是否为质数 . . \n";
    // 等待函数 fnPrime 返回
    // bool bobj = fobj.get();
    if (true)
        std::cout << "给出的数字是质数 . . .  ! \n";
    else
        std::cout << "给出的数字不是质数 . . .  ! \n\n";
    return 0;
}
g++ -std=c++11 -pthread ...
检查数字4是否为质数 . . 
给出的数字是质数 . . .  ! 
处理开始。。。请等待。。。
处理数值20  1
处理数值20  2
...
  • 示例2
// library for std::cout
#include <iostream>
// library for std::async and std::future
#include <future>
// library for std::string
#include <string>
std::string samplefunction(const std::string& st) {
    return "This is the output of " + st;
}
class SamplefunctionObject {
   public:
    std::string operator()(const std::string& st) const {
        return "This is the output of " + st;
    }
};
int main() {
    std::cout << std::endl;
    // future with the help of function
    auto ff = std::async(samplefunction, "sample function");
    // future with the help of function object
    SamplefunctionObject samplefunctionObject;
    auto ffo = std::async(samplefunctionObject, "sample function object");
    // future with the help of lambda function
    auto fl = std::async(
        [](const std::string& st) { return "This is the output of " + st; },
        " lambda function");
    std::cout << ff.get() << "\n" << ffo.get() << "\n" << fl.get() << std::endl;
    std::cout << std::endl;
}
This is the output of sample function
This is the output of sample function object
This is the output of  lambda function
### C++ `std::async` 的使用与配置 #### 什么是 `std::async` `std::async` 是 C++11 中引入的一个工具函数,用于启动异步任务。它返回一个 `std::future` 对象,该对象可以用来获取异步任务的结果或状态。 通过调用 `std::async()` 函数,默认情况下会以 `std::launch::async` 方式运行任务[^1]。这意味着任务会在单独的线程上执行。然而,也可以指定其他策略来控制任务的行为。 --- #### 基本语法 以下是 `std::async` 的基本语法: ```cpp template< class Function, class... Args > std::future<typename std::result_of<Function(Args...)>::type> async( std::launch policy, Function&& f, Args&&... args ); ``` 参数解释: - **policy**: 启动策略,可以选择 `std::launch::async` 或 `std::launch::deferred`。 - `std::launch::async`: 创建新线程并立即执行任务。 - `std::launch::deferred`: 将任务延迟到第一次访问结果时才执行。 - **f**: 要执行的任务函数或可调用对象。 - **args**: 提供给任务函数的参数列表。 --- #### 示例代码 下面是一个简单的例子,展示如何使用 `std::async` 来计算两个数之和: ```cpp #include <iostream> #include <future> int add(int a, int b) { return a + b; } int main() { // 使用 std::launch::async 策略 std::future<int> result = std::async(std::launch::async, add, 5, 7); // 获取异步任务的结果 std::cout << "Result: " << result.get() << std::endl; return 0; } ``` 在这个例子中,`add` 函数被作为异步任务提交给 `std::async` 执行,并且其结果可以通过 `std::future` 对象获得。 --- #### 默认行为 vs 显式策略 如果不显式提供启动策略,则默认采用 `std::launch::async | std::launch::deferred` 组合模式。这表示标准库会选择一种合适的策略来优化性能。如果希望强制某种特定行为,可以在调用时传递相应的枚举值。 例如,仅允许延迟执行: ```cpp std::future<int> deferred_result = std::async(std::launch::deferred, add, 3, 4); ``` 或者只允许并发执行: ```cpp std::future<int> async_result = std::async(std::launch::async, add, 3, 4); ``` --- #### 结果同步机制 当需要等待异步任务完成时,可以调用 `std::future::get()` 方法。此方法会阻塞当前线程直到任务结束为止。另外还有非阻塞方式检查任务的状态,比如利用 `wait_for` 和 `wait_until` 成员函数。 示例演示超时检测功能: ```cpp if (result.wait_for(std::chrono::seconds(2)) == std::future_status::ready) { std::cout << "Task completed within timeout." << std::endl; } else { std::cout << "Timeout occurred before task finished!" << std::endl; } ``` 上述片段展示了设置最大等待时间为两秒钟的情况下的处理逻辑。 --- #### 配置注意事项 为了确保正确使用 `std::async`,需要注意以下几点事项: 1. 如果多个地方频繁依赖于同一份数据资源,在设计阶段就要考虑加锁保护共享变量; 2. 不要忘记释放不再使用的 future 实例以防内存泄漏; 3. 编译器支持情况可能有所不同,请确认目标平台已启用相应特性开关(如 `-std=c++11`)[^2]。 --- #### 日志集成实例 结合前面提到的日志框架 spdlog ,我们可以构建更复杂的场景应用案例。假设我们需要记录大量调试信息而不影响主流程效率,那么就可以借助异步工厂简化开发过程[^3]: ```cpp #include "spdlog/spdlog.h" #include "spdlog/async.h" void setup_async_logger() { try { spdlog::init_thread_pool(8192, 1); // 设置缓冲区大小以及工作线程数量 auto console_sink = std::make_shared<spdlog::sinks::stdout_color_sink_mt>(); // 注册新的异步日志器 auto logger = spdlog::create_async<std::mutex>("my_async_logger", console_sink); logger->info("This is an asynchronous log message."); } catch(const spdlog::spdlog_ex& ex){ std::cerr << "Log initialization failed: " << ex.what() << '\n'; } } int main(){ setup_async_logger(); return 0; } ``` 这里我们定义了一个名为 `setup_async_logger` 的辅助函数负责初始化环境,并启用了多线程安全版本的标准输出颜色化终端接收端口。最终实现了高效稳定的后台打印效果。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

-西门吹雪

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值