“Asynchronous programming with futures and await” by Artur Laksberg

Download Report

Transcript “Asynchronous programming with futures and await” by Artur Laksberg

3
string read_string_from_file(string file);
string s = read_string_from_file("myfile.txt");
cout << s;
template<typename Func>
void read_string_from_file(string file, Func&& func);
...
read_string_from_file("myfile.txt", [](string s) {
cout << s;
});
template<typename Func>
void concatenate_files(string file1, string file2, Func&& func)
{
read_string_from_file(file1, [func](string str1) {
read_string_from_file(file2, [func](string str2) {
func(str1 + str2);
});
});
}
template<typename Func>
void concatenate_files(string file1, string file2, Func&& func) {
auto results = make_shared<result_holder>();
read_string_from_file(file1, [=](string str) {
if (results->str) {
func(str + *results->str);
}
else{
results->str = make_unique<string>(str);
}
});
read_string_from_file(file2, [=](string str) {
if (results->str) {
func(*results->str + str);
}
else{
results->str = make_unique<string>(str);
}
});
}
struct result_holder
{
unique_ptr<string> str;
};
?
Spot
the
defect!
// Launch a task:
future<int> work = async([] { return CountLinesInFile(…); });
// Collect the results:
cout << work.get();
// Launch a task:
future<int> work = CountLinesInFileAsync(...);
work.then([] (future<int> f) {
// Get the result
cout << f.get();
});
future<T1> t = async([]()
{
return func1();
}).then ([](future<T1> n)
{
return func2(n.get());
}).then ([](future<T2> n)
{
return func3(n.get());
}).then ...
f.then(A).then(B);
f.then(A);
f.then(B);
auto f = when_all(a, b);
auto f = when_any(a, b);
vector<future<int>> futures = get_futures();
auto futureResult =
when_all (begin(futures), end(futures))
.then([](future<vector<future<string>>> results) {
for (auto& s : results.get() ) // will not block
{
cout << s.get(); // will not block
}
});
future<int> future1 = ...;
future<string> future2 = ...;
auto futureResult =
when_all(future1, future2)
.then([](future<tuple<future<int>, future<string>>> results) {
auto pair = results.get(); // will not block
...
}
});
future<string> concatenate_files(string file1, string file2)
{
auto strings = when_all(read_string_from_file(file1),
read_string_from_file(file2));
return strings.then([](
future<tuple<future<string>, future<string>>> strings) {
auto pair = strings.get();
return pair.get<0>.get() + pair.get<1>.get();
});
}
future<string> concatenate_files(string file1, string file2)
{
auto strings = when_all(read_string_from_file(file1),
read_string_from_file(file2));
return strings.then([](
auto strings) {
auto pair = strings.get();
return pair.get<0>.get() + pair.get<1>.get();
});
}
vector<future<int>> futures = get_futures();
auto futureResult =
when_any (begin(futures), end(futures))
.then([](future<vector<future<string>>> results) {
for (auto& s : results.get() ) // will not block
{
if(s.ready())
cout << s.get(); // will not block
}
});
future<int> compute(int x) {
if (x < 0) return make_ready_future<int>(-1);
if (x == 0) return make_ready_future<int>(0);
future<int> f1 = async([]() { return do_work(x); });
return f1;
}
future<int> f1 = async([]() { return possibly_long_computation(); });
if(!f1.is_ready()) {
//if not ready, attach a continuation and avoid a blocking wait
fl.then([] (future<int> f2) {
int v = f2.get();
process_value(v);
});
}
// if ready, no need to add continuation, process value right away
else {
int v = f1.get();
process_value(v);
}
.get
string read(string file)
{
istream fi = open(file).get();
string ret, chunk;
while ((chunk = fi.read().get()).size())
ret += chunk;
return ret;
}
.then
future<string> read(string file)
{
return open(file)
.then([=](istream fi) {
string ret, chunk;
while (
???
22
.get
string read(string file)
{
istream fi = open(file).get();
string ret, chunk;
while ((chunk = fi.read().get()).size())
ret += chunk;
return ret;
}
.then
future<string> read(string file)
{
return open(file)
.then([=](istream fi) {
auto ret = make_shared<string>();
auto next =
make_shared<function<future<string>()>>(
[=] {
fi.read()
.then([=](string chunk) {
if (chunk.size()) {
*ret += chunk;
return next();
}
return make_ready_future(*ret);
});
});
return (*next)();
});
23
}
future<string> f() resumable
{
future<int> f1 = async([]() {
return possibly_long_computation(); });
int n = await f1;
return to_string(n);
}
.get
string read(string file)
{
istream fi = open(file).get();
string ret, chunk;
while ((chunk = fi.read().get()).size())
ret += chunk;
return ret;
}
await
String read(string file)
{
istream fi = await open(file);
string ret, chunk;
while ((chunk = (await fi.read()).size())
ret += chunk;
return ret;
}
26
void foo()
{
task<bool> t = async_bar();
somefunc();
bool b = t.get();
}
task<bool>
async_bar() resumable
{
do_work();
...
// sync calls
await async_work();
// More sync calls
...
return true;
}
task<void>
async_work() resumable
{
do_work();
await create_task( [] {
longrunning ();
});
return;
}
<blocked>
bool
b = t.get()
t = somefunc();
async_bar()
foo();
<completed>
done!
<suspended>
…
…
…
…
…
…
…
awaitsync
async_work();
do_work();
More
calls
…
async_bar();
return true;
Main Stack
Thread #1
Side Stack
async_work
is done!
return task<void>
<completed>
<suspended>
await create_task();
do_work();
async_work();
return;
Side Stack
Thread #2
27
Longrunning is
done!