c++ boost future和lazy future

时间:2021-06-30 23:37:29
  • 程序流中常见的情况是,中间一段代码需要长时间运行,然后蛋疼的是后面一段代码需要这段中间代码的计算结果。比如这段代码是UI,或者这段代码是图像识别或者图形渲染等计算密集型的代码。
  • 以前笨拙的处理方式是,新开启一个线程去调用这段长时间运行的代码,并在线程内设置状态变量标记,表示计算完成与否。然后在之前的线程里判断状态标记以决定是否循环等待或者继续往下走码。
  • 这里面还牵扯到的概念是同步和异步。参见几年之前一篇博文Linux文件IO理解

很有幸,future比较好地解决了这些问题。std和boost都有相应的实现。
对于同步处理的情况,示例代码如下:

// a non-optimized way of checking for prime numbers:
bool is_prime(int x) {
    for (int i = 2; i < x; ++i) if (x%i == 0) return false;
    return true;
}
//std::future
int testStdFuture()
{
    // call function asynchronously:
    std::future<bool> fut = std::async(is_prime, 194232491);

    std::cout << "checking...\n";
    fut.wait();

    std::cout << "\n194232491 ";
    if (fut.get())      // guaranteed to be ready (and not block) after wait returns
        std::cout << "is prime.\n";
    else
        std::cout << "is not prime.\n";

    return 0;
}

using namespace boost::this_thread;

// boost的future
int testBoostFuture()
{
    boost::packaged_task<bool> pt(boost::bind(is_prime, 194232491));
    unique_future <bool> f = pt.get_future();

    boost::thread(boost::move(pt));
    cout << "fab" << (f.is_ready() == true) << (f.has_value() == true) << endl;
    f.wait();
    assert(f.is_ready() && f.has_value());
    std::cout << "\n194232491 ";
    if (f.get())      // guaranteed to be ready (and not block) after wait returns
        std::cout << "is prime.\n";
    else
        std::cout << "is not prime.\n";

    return 0;
}

更精彩的是lazy future,实现了在完成长时运算的延迟调用(并不是真的异步调用,因为会在f.get()有值之前进行长时计算,并且处于同一个线程。所以仍然有改进的空间!!),不需要主动等待和状态判断了,而是在需要知道计算结果的时候,就恰好能知道结果。这种感觉就像飞一样。


void lazy_call_back(boost::packaged_task<bool>& task)
{
    try
    {
        task(); // 会调用直到取出结果
    }
    catch (boost::task_already_started&)
    {
    }
}

int testBoostLazyFuture()
{
    boost::packaged_task<bool> task(boost::bind(is_prime, 194232491));
    task.set_wait_callback(lazy_call_back);

    unique_future <bool> f = task.get_future();

    std::cout << "\n194232491 ";
    if (f.get())      // guaranteed to be ready (and not block) after wait returns
        std::cout << "is prime.\n";
    else
        std::cout << "is not prime.\n";

    return 0;
}