返回异步结果 - 有效处理同步情况

3
你可以像这样拥有一个异步API。
std::future<int> GetAsync()

有时候,例如当您已经缓存了结果并且想要返回初始化为该结果的 future 时,是否有一种不需要创建额外的 std::promise 或使用附带 launch policy deferred 的额外 async 的方法来实现?当前标准(或提案)是否有这种方式?
编辑:还需考虑基于 GetAsync() 函数局部状态计算结果的情况以及捕获该状态可能需要按值捕获的需求,以防选择使用带有延迟启动策略的 std::async。

过早的优化是万恶之源。 - ronag
我并不认为这是一种过早的优化。你有一个大多数情况下都是异步的API,但在许多情况下它会在同一线程上处理响应,因此你必须问自己如何在同步情况下返回。 - Ghita
1
正如您所建议的,使用 promise 或延迟 async - ronag
2个回答

10

我显然误解了什么,为什么你不能只是这样做:

std::future<int> GetAsync()
{
  if (/*already got result*/)
  {
    std::promise<int> p;
    p.set_value(/*result*/);
    return p.get_future();
  }  
  return std::async(/*whatever is needed*/);
}

创建一个Promise有什么问题吗?如果你想从一个未来(异步返回对象)中获取结果,你需要一个异步提供者,而promise就是这样一种类型。


这是我实现它的方式,但这似乎是一个相当常见的用例,因此来自n3428的提案 - http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3428.pdf - Ghita
我不明白为什么N3428说这是非平凡的,对我来说看起来相当平凡。如果程序员无法理解这三行代码,他们不应该编写C++,更不用说多线程C++了。 - Jonathan Wakely
@rhalbersma,上面的相关代码几乎与多线程无关。创建一个对象,设置一个值,返回该值的包装器。这很简单。我不指望任何人有多线程的经验,但我希望他们能够理解上面的三行代码。如果有人无法应对这个问题,那么他们也无法应对多线程,并且拥有“make_future”函数也无法改变这一点。 - Jonathan Wakely
1
我已经明确表达了我的意见,我不同意他们,这很琐碎。你无法说服我改变看法。 - Jonathan Wakely
@JonathanWakely 实际上,我认为这仍然是一个性能问题。能够返回一个包含请求值的状态的future对象应该更有效,因为promise.set_value()使用同步来设置“共享状态”。 - Ghita
显示剩余2条评论

0
关于 futures 和 promises 的事情是它们被设计用于多线程使用。因此,如果您想返回一个 future 对象,您需要通过 std::async 调用、std::packaged_task<>std::promise<> 来创建它。如果是这种情况,@ronag 的答案就是一个好选择。
如果这不是一般情况,而您只想返回对您的值的间接引用,您可以使用 std::function 进行直接计算,或者在其周围使用 缓存机制,或者使用 Expected<T> 值来处理错误,就像 futures 一样;这样您就不必支付线程通信成本。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接