我正在学习异步编程,而且我经常发现自己编写的代码如下:
fooAsync(input, [=](Output output) {
// ...
asyncA(output, [=](OutputA outputA) {
// ...
asyncB(outputA, [=](OutputB outputB) {
// ...
asyncC(outputB, [=](OutputC outputC) {
// ...
asyncD(outputC, [=](OutputD outputD) {
...;
});
});
});
});
});
使用c ++ 11,有没有办法很好地组织上面的代码?非常感谢!
答案 0 :(得分:3)
template<class T>
struct my_future:std::shared_future<T> {
using std::shared_future<T>::shared_future;
template<class F>
auto operator->*( F f )&&
-> my_future< std::decay_t<decltype(f(std::declval<T const&>()))> >
{
auto self = std::move(*this);
return std::async( std::launch::async,
[f, self]() mutable ->decltype(std::declval<F&>()(std::declval<T const&>())){
return f(self.get());
}
);
}
};
现在,您的Async
函数返回my_future<Output>
。
您只需使用->*
链接它们。
专攻void
个:
template<>
struct my_future<void>:std::shared_future<void> {
using std::shared_future<void>::shared_future;
template<class F>
auto operator->*( F f )&&
-> my_future< std::decay_t<decltype(f())> >
{
auto self = std::move(*this);
return std::async( std::launch::async,
[f, self]() mutable ->decltype(std::declval<F&>()()){
self.wait();
return f();
}
);
}
};
测试代码:
my_future<int> f = std::async( []{ return 7; } );
auto f2 = std::move(f)->*[](int x){ return x*2; };
std::cout << f2.get() << '\n';
auto f3 = std::move(f2)->*[](int y){}->*[]{ return 42; };
std::cout << f3.get() << '\n';
基本上这是在实施.then
并使用future
s。
您的代码变为:
fooAsync(input)
->*[=](Output output) {
// ...
return asyncA(output);
}
->*[=](OutputA outputA) {
// ...
return asyncB(outputA);
}
->*[=](OutputB outputB) {
// ...
return asyncC(outputB);
}
->*[=](OutputC outputC) {
// ...
return asyncD(outputC);
}
->*[=](OutputD outputD) {
...;
};
请注意,可以在其他地方生成,存储,传递和处理中间值。
另请注意,可以增加期货以启动更少的线程。
想象一下,您的增强型未来有可选&#34;延续&#34; (返回void)小心地用互斥量包裹。
以下是伪代码:
template<class T>
struct future_state {
mutable std::mutex m;
std::condition_variable cv;
std::optional<T> value;
std::function<void(T&&)> continuation;
void set_value( T&& t ) {
{
auto l = lock();
if (continuation)
return continuation( std::forward<T>(t) );
value.emplace( std::forward<T>(t) );
}
cv.notify_one();
}
bool has_value() const {
auto l = lock();
return (bool) value;
}
bool has_continuation() const {
auto l = lock();
return (bool) continuation;
}
std::unique_lock<std::mutex> lock() const {
return std::unique_lock<std::mutex>(m);
}
T get_value() const {
auto l = lock();
cv.wait( l, [&]{ return (bool)value; } );
T r = std::move(*value);
value = std::nullopt;
return r;
}
// etc
};
template<>
struct future_state<void> {
// TODO
现在使用std::shared_future
或shared_ptr<future_state>
方法围绕.then
包围->*
类似界面,或者附加延续(如果旧版本未完成) )或者用新的努力启动一个新的线程(如果旧的完成),并返回结果的未来。
现在您的异步代码可能更喜欢管理自己的线程/异步。 A&#34;同步延续&#34;如果任务已经准备就绪,那么没有启动新线程的工作相当不错,并且如果它还没有准备就可以继续未来状态。
这一切都不容易;它是线程代码。查看.then
std::future
的实施可能具有启发性。