Asynchronous programming with futures and await

29
Artur Laksberg Microsoft May 8th, 2014 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 Presentation

Transcript of Asynchronous programming with futures and await

Page 1: Asynchronous programming with futures and await

Artur LaksbergMicrosoft May 8th, 2014

Asynchronous programming with futures and await

Page 2: Asynchronous programming with futures and await

Agenda• Asynchrony with callbacks• Futures and Continuations• Composition with futures• await

Page 3: Asynchronous programming with futures and await

Hollywood Principle

Don’t call us, we’ll call you!3

Page 4: Asynchronous programming with futures and await

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

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

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

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

std::future<T>std::shared_future<T>

Page 9: Asynchronous programming with futures and await

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

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

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

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

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

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

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

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

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

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

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

awaitand resumable functions

Page 21: Asynchronous programming with futures and await

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

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
Page 24: Asynchronous programming with futures and await

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

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

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

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

“Concurrent programs wait faster”

Tony Hoare

Page 29: Asynchronous programming with futures and await