清理一个超时的未来

Clean-up a timed-out future

本文关键字:一个 超时 未来      更新时间:2024-09-26

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

下面是一个(极大地(简化的示例代码来强调这个问题。(事实上,这是一个始终运行的、高可用的应用程序。在那里,我首先从缓存中读取,只有当缓存中有过时的数据时,我才会尝试从数据库中读取。但是,如果数据库查询耗时很长,我需要继续处理过时的数据。(

我的问题是,在未来阅读超时的情况下,我是否必须单独处理未来的清理工作(即保留一份副本,并不时检查是否准备好(?或者我可以简单地忽略它(即保持代码原样(。

/* 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`?
}

我的问题是,在未来读取超时的情况下,我是否必须单独处理未来的清理(即保留一份副本,并不时检查它是否准备好(?或者我可以简单地忽略它(即保持代码原样(。

从我个人的角度来看,这取决于你想要什么。在当前(最小(实现下,getValue函数将被未来的析构函数阻塞(请参阅cppreference页面和一些SO问题(。

如果你不想要阻塞行为,有一些解决方案,正如这个问题中提出的,比如:

  1. future移动到某个外部范围
  2. 使用分离的执行器和一些方便的代码/数据结构来处理返回状态
  3. 看看是否可以用一些超时支持I/O操作(如选择/轮询(替换future

等。