清理超时的未来

Clean-up a timed-out future

我需要 运行 一个带有超时的函数。如果它没有在给定的超时内 return,我需要丢弃它并回退到不同的方法。

以下是一个(大大)简化的示例代码以突出问题。 (实际上,这是一个总是 运行ning 的高可用应用程序。我首先从缓存中读取,然后仅当缓存中有陈旧数据时才尝试从数据库中读取。但是,如果数据库查询时间很长,我需要继续处理过时的数据。)

我的问题是,如果 future 读取超时,我是否必须单独处理 future 的清理(即保留副本并不时检查它是否准备就绪)?或者我可以简单地忽略它(即保持代码不变)。

/* DB query can be time-consuming, but the result is fresh */
string readFromDatabase(){
  // ...
  // auto dbValue = db.query("select name from users where id=" + _id);
  // ...
  return dbValue;
}

/* Cache query is instant, but the result could be stale */
string readFromLocalCache(){
  // ...
  // auto cachedVal = _cache[_id];
  // ...
  return cachedVal;
}

int getValue(){
  // Idea:
  //  - Try reading from the database.
  //  - If the db query didn't return within 1 second, fallback to the other method.
  
  using namespace std::chrono_literals;

  auto fut = std::async(std::launch::async, [&](){ return readFromDatabase(); });
  switch (fut.wait_for(1s)){
    case std::future_status::ready: // query returned within allotted time
    {
      auto freshVal = fut.get();
      // update cache
      return freshVal;
    }
    case std::future_status::timeout: // timed out, fallback ------ (*)
    {
      break;
    }
    case std::future_status::deferred: // should not be reached
    {
      break;
    }
  }
  return readFromLocalCache();
  // quetion? what happens to `fut`?
}

My question is, in the case where the future read timed out, do I have to handle the clean-up of the future separately (i.e. keep a copy and check if it is ready time-to-time)? or can I simply ignore it (i.e. keep the code as is).

从我个人的角度来看,这取决于你想要什么。在您当前的(最小)实现下,getValue 函数将被未来的析构函数阻止(参见 cppreference page and some SO questions)。

如果您不想要阻塞行为,有一些解决方案,如本 question 中所建议的,例如:

  1. future 移动到某个外部范围
  2. 使用分离的执行器和一些方便的 code/data 结构来处理 return 状态
  3. 看看是否可以用一些超时支持 I/O 操作替换 future,例如 select/poll

等等