Presentation is loading. Please wait.

Presentation is loading. Please wait.

C++ await Deon Brewis std::future additions:

Similar presentations


Presentation on theme: "C++ await Deon Brewis std::future additions:"— Presentation transcript:

1 C++ await Deon Brewis std::future additions:
isocpp.org/files/papers/N3721.pdf resumable functions: isocpp.org/files/papers/N3722.pdf

2 PPL vs. std::future PPL std::future Requires future.then – i.e. N3721
concurrency::task<int> Calc( int x, int y ) resumable { int i = await concurrency::create_task( [=] { return x + y; } ); return i + 42; } std::future<int> Calc( int x, int y ) resumable { int i = await std::async( [=] { return x + y; } ); return i + 42; } Requires future.then – i.e. N3721

3 Motivation .get(), .then() and await comparison

4 Simple case .get size_t file_sizes( string file1, string file2 ) {
task<file> f1 = open(file1); task<file> f2 = open(file2); return f1.get().size() + f2.get().size(); }

5 Simple case .get .then size_t file_sizes( string file1, string file2 ) { task<file> f1 = open(file1); task<file> f2 = open(file2); return f1.get().size() + f2.get().size(); } task<size_t> file_sizes( string file1, string file2 ) { task<file> f1 = open(file1); task<file> f2 = open(file2); return f1.then( [f2] (task<file> tr1 ) { f2.then( [tr1] (task<file> tr2) return tr1.get().size() + tr2.get().size(); }) }); }

6 Simple case .get .then .then + await
size_t file_sizes( string file1, string file2 ) { task<file> f1 = open(file1); task<file> f2 = open(file2); return f1.get().size() + f2.get().size(); } task<size_t> file_sizes( string file1, string file2 ) { task<file> f1 = open(file1); task<file> f2 = open(file2); return f1.then( [f2] (task<file> tr1 ) { f2.then( [tr1] (task<file> tr2) return tr1.get().size() + tr2.get().size(); }) }); } .then + await task<size_t> file_sizes( string file1, string file2 ) resumable { task<file> f1 = open(file1); task<file> f2 = open(file2); return (await f1).size() + (await f2).size(); }

7 Branches and loops ? .get .then
string read( string file, string suffix ) { istream fi = open(file).get(); string ret, chunk; while( (chunk = fi.read().get()).size() ) ret += chunk + suffix; return ret; } task<string> read( string file, string suffix ) { return open(file) .then([=](istream fi) { string ret, chunk; while( ?

8 Branches and loops .get .then
string read( string file, string suffix ) { istream fi = open(file).get(); string ret, chunk; while( (chunk = fi.read().get()).size() ) ret += chunk + suffix; return ret; } task<string> read( string file, string suffix ) { return open(file) .then([=](istream fi) { auto ret = make_shared<string>(); auto next = make_shared<std::function<task<string>()>>( [=] { fi.read() .then([=](string chunk) { if( chunk.size() ) { *ret += chunk + suffix; return next(); } return task_from_result(*ret); }); return (*next)();

9 Branches and loops .get .then .then + await
string read( string file, string suffix ) { istream fi = open(file).get(); string ret, chunk; while( (chunk = fi.read().get()).size() ) ret += chunk + suffix; return ret; } task<string> read( string file, string suffix ) { return open(file) .then([=](istream fi) { auto ret = make_shared<string>(); auto next = make_shared<std::function<task<string>()>>( [=] { fi.read() .then([=](string chunk) { if( chunk.size() ) { *ret += chunk + suffix; return next(); } return task_from_result(*ret); }); return (*next)(); .then + await task<string> read( string file, string suffix ) resumable { istream fi = await open(file); string ret, chunk; while( (chunk = await fi.read()).size() ) ret += chunk + suffix; return ret; }

10 Technical drill-down

11 Await implementations
Iterator-Based Co-routines Rewrite resumable function into a resumable state machine Requires all locals to be hoisted to the heap Resumable Side Stacks Do not rewrite function logic Each resumable function execution has its own “side” stack Side stack lives beyond suspension/resuming until logical completion C# C++ IBC: harder to implement in our current compiler (temp lifetime); also slower for C++ (ctor and dtor calls need to be injected) RSS: A sidestack requires 8k commit (4k + guard page), it reserves 1MB ASLA: for scalability reasons (supporting >1million concurrent resumable functions)

12 Resumable Side Stack simulation
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 await create_task( [] { longrunning (); }); return; Thread #1 Thread #2 Main Stack Side Stack Side Stack <blocked> <completed> done! somefunc(); bool b = t.get() t = async_bar() <suspended> foo(); async_work is done! Longrunning is done! <completed> return task<bool> <suspended> return task<void> do_work(); More sync calls await async_work(); do_work(); await create_task(); return true; async_bar(); async_work(); return;

13 Demo


Download ppt "C++ await Deon Brewis std::future additions:"

Similar presentations


Ads by Google