asynchronous programming with futures and await
DESCRIPTION
Asynchronous programming with futures and await. Artur Laksberg Microsoft May 8th, 2014. Agenda. Asynchrony with callbacks Futures and Continuations Composition with futures await. Hollywood Principle. - PowerPoint PPT PresentationTRANSCRIPT
![Page 1: Asynchronous programming with futures and await](https://reader030.vdocuments.mx/reader030/viewer/2022033022/56816356550346895dd40261/html5/thumbnails/1.jpg)
Artur LaksbergMicrosoft May 8th, 2014
Asynchronous programming with futures and await
![Page 2: Asynchronous programming with futures and await](https://reader030.vdocuments.mx/reader030/viewer/2022033022/56816356550346895dd40261/html5/thumbnails/2.jpg)
Agenda• Asynchrony with callbacks• Futures and Continuations• Composition with futures• await
![Page 3: Asynchronous programming with futures and await](https://reader030.vdocuments.mx/reader030/viewer/2022033022/56816356550346895dd40261/html5/thumbnails/3.jpg)
Hollywood Principle
Don’t call us, we’ll call you!3
![Page 4: Asynchronous programming with futures and await](https://reader030.vdocuments.mx/reader030/viewer/2022033022/56816356550346895dd40261/html5/thumbnails/4.jpg)
Read From FIle: Naïve SolutionReturn a string, block on call:string read_string_from_file(string file);
string s = read_string_from_file("myfile.txt");cout << s;
Problem: blocking call
![Page 5: Asynchronous programming with futures and await](https://reader030.vdocuments.mx/reader030/viewer/2022033022/56816356550346895dd40261/html5/thumbnails/5.jpg)
Read From FIle: Callback SolutionDoes not return a string, takes a callback that accepts a string:template<typename Func>void read_string_from_file(string file, Func&& func);
...read_string_from_file("myfile.txt", [](string s) { cout << s;});
![Page 6: Asynchronous programming with futures and await](https://reader030.vdocuments.mx/reader030/viewer/2022033022/56816356550346895dd40261/html5/thumbnails/6.jpg)
Concatenate Files: Naive SolutionRead from one file, then read from another: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); }); });}
![Page 7: Asynchronous programming with futures and await](https://reader030.vdocuments.mx/reader030/viewer/2022033022/56816356550346895dd40261/html5/thumbnails/7.jpg)
Concatenate Files: A “Better” Solutiontemplate<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!
![Page 8: Asynchronous programming with futures and await](https://reader030.vdocuments.mx/reader030/viewer/2022033022/56816356550346895dd40261/html5/thumbnails/8.jpg)
std::future<T>std::shared_future<T>
![Page 9: Asynchronous programming with futures and await](https://reader030.vdocuments.mx/reader030/viewer/2022033022/56816356550346895dd40261/html5/thumbnails/9.jpg)
Long-Running WorkCounting lines in a file// Launch a task:future<int> work = async([] { return CountLinesInFile(…); });
// Collect the results:cout << work.get();
Problem: blocking call
![Page 10: Asynchronous programming with futures and await](https://reader030.vdocuments.mx/reader030/viewer/2022033022/56816356550346895dd40261/html5/thumbnails/10.jpg)
Proposal: Continuation(shared_)future::then
// Launch a task:future<int> work = CountLinesInFileAsync(...);
work.then([] (future<int> f) { // Get the result cout << f.get();});
![Page 11: Asynchronous programming with futures and await](https://reader030.vdocuments.mx/reader030/viewer/2022033022/56816356550346895dd40261/html5/thumbnails/11.jpg)
Binding Multiple Continuationsfuture<T1> t = async([](){ return func1();}).then ([](future<T1> n){ return func2(n.get());}).then ([](future<T2> n){ return func3(n.get());}).then ...
![Page 12: Asynchronous programming with futures and await](https://reader030.vdocuments.mx/reader030/viewer/2022033022/56816356550346895dd40261/html5/thumbnails/12.jpg)
Advanced CompositionSequential Composition:
Parallel Composition (only shared_future):f.then(A).then(B);
f.then(A);f.then(B);
Join and Choice (more on next page):auto f = when_all(a, b);auto f = when_any(a, b);
![Page 13: Asynchronous programming with futures and await](https://reader030.vdocuments.mx/reader030/viewer/2022033022/56816356550346895dd40261/html5/thumbnails/13.jpg)
JoinCreate a future that completes when all arguments completevector<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 } });
![Page 14: Asynchronous programming with futures and await](https://reader030.vdocuments.mx/reader030/viewer/2022033022/56816356550346895dd40261/html5/thumbnails/14.jpg)
JoinNow with heterogeneous argumentsfuture<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 ... }});
![Page 15: Asynchronous programming with futures and await](https://reader030.vdocuments.mx/reader030/viewer/2022033022/56816356550346895dd40261/html5/thumbnails/15.jpg)
Concatenate Files: The Right SolutionTerse, efficient and safefuture<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(); });}
![Page 16: Asynchronous programming with futures and await](https://reader030.vdocuments.mx/reader030/viewer/2022033022/56816356550346895dd40261/html5/thumbnails/16.jpg)
Concatenate Files: The Right SolutionTerse, efficient and safe (with polymorphic lambdas)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(); });}
![Page 17: Asynchronous programming with futures and await](https://reader030.vdocuments.mx/reader030/viewer/2022033022/56816356550346895dd40261/html5/thumbnails/17.jpg)
ChoiceCreate a future that completes when at least one of arguments completes: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 } });
![Page 18: Asynchronous programming with futures and await](https://reader030.vdocuments.mx/reader030/viewer/2022033022/56816356550346895dd40261/html5/thumbnails/18.jpg)
make_ready_futurefuture<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;}
![Page 19: Asynchronous programming with futures and await](https://reader030.vdocuments.mx/reader030/viewer/2022033022/56816356550346895dd40261/html5/thumbnails/19.jpg)
is_readyfuture<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);}
![Page 20: Asynchronous programming with futures and await](https://reader030.vdocuments.mx/reader030/viewer/2022033022/56816356550346895dd40261/html5/thumbnails/20.jpg)
awaitand resumable functions
![Page 21: Asynchronous programming with futures and await](https://reader030.vdocuments.mx/reader030/viewer/2022033022/56816356550346895dd40261/html5/thumbnails/21.jpg)
Branches and loops
22
.get .thenstring read(string file){ istream fi = open(file).get(); string ret, chunk; while ((chunk = fi.read().get()).size()) ret += chunk; return ret;}
future<string> read(string file) { return open(file) .then([=](istream fi) { string ret, chunk; while (
???
![Page 22: Asynchronous programming with futures and await](https://reader030.vdocuments.mx/reader030/viewer/2022033022/56816356550346895dd40261/html5/thumbnails/22.jpg)
Branches and loops
23
.get .thenstring read(string file){ istream fi = open(file).get(); string ret, chunk; while ((chunk = fi.read().get()).size()) ret += chunk; return ret;}
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)(); });}
![Page 23: Asynchronous programming with futures and await](https://reader030.vdocuments.mx/reader030/viewer/2022033022/56816356550346895dd40261/html5/thumbnails/23.jpg)
![Page 24: Asynchronous programming with futures and await](https://reader030.vdocuments.mx/reader030/viewer/2022033022/56816356550346895dd40261/html5/thumbnails/24.jpg)
Await ExampleGet a value, convert to string:
future<string> f() resumable{ future<int> f1 = async([]() { return possibly_long_computation(); });
int n = await f1; return to_string(n);}
![Page 25: Asynchronous programming with futures and await](https://reader030.vdocuments.mx/reader030/viewer/2022033022/56816356550346895dd40261/html5/thumbnails/25.jpg)
Branches and loops, with await
26
.get awaitstring read(string file){ istream fi = open(file).get(); string ret, chunk; while ((chunk = fi.read().get()).size()) ret += chunk; return ret;}
String read(string file){ istream fi = await open(file); string ret, chunk; while ((chunk = (await fi.read()).size()) ret += chunk; return ret;}
![Page 26: Asynchronous programming with futures and await](https://reader030.vdocuments.mx/reader030/viewer/2022033022/56816356550346895dd40261/html5/thumbnails/26.jpg)
Thread #2Thread #1
Resumable Side Stack Simulation
27
Main Stack
………
……
foo();t = async_bar()
Side Stackasync_bar();
do_work();………
await async_work();
somefunc();bool b = t.get()
<blocked>
More sync calls…
return true;
<completed>
Side Stackasync_work();
do_work();await create_task();
Longrunning is done!<suspended
>return task<void>
<suspended>return task<bool>
return;
<completed>
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;}
done!async_work
is done!
![Page 27: Asynchronous programming with futures and await](https://reader030.vdocuments.mx/reader030/viewer/2022033022/56816356550346895dd40261/html5/thumbnails/27.jpg)
References• N3857: Improvements to std::future<T> and
Related APIs• N3858: Resumable Functions• N3970: Working Draft, Information technology –
Programming languages, their environments and system software interfaces – C++ Extensions for Concurrency
![Page 28: Asynchronous programming with futures and await](https://reader030.vdocuments.mx/reader030/viewer/2022033022/56816356550346895dd40261/html5/thumbnails/28.jpg)
“Concurrent programs wait faster”
Tony Hoare
![Page 29: Asynchronous programming with futures and await](https://reader030.vdocuments.mx/reader030/viewer/2022033022/56816356550346895dd40261/html5/thumbnails/29.jpg)