Visual C++ 2015提供了一個Coroutine的實驗性實作,未來可能會被列入C++17 當中,因此先來體驗一下
Generator 這寫法就跟Python差不多了,直接用yield
就行了 不過跟Javascript的Generator還是有一定程度的不同
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 #include <iostream> #include <experimental/generator> using namespace std ::experimental;using namespace std ;generator<int > fib () { int a = 0 ; int b = 1 ; for (;;) { yield a; auto next = a + b; a = b; b = next; } } int main (int argc, char * argv[]) { for (auto v : fib()) { if (v > 50 ) break ; cout << v << endl ; } }
async function 以下是個示範程式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 #include <future> #include <iostream> using namespace std ;using namespace std ::chrono;future <int > calculate_the_answer () { return async([] { this_thread::sleep_for(1 s); return 42 ; }); } future <void > coro () { cout << this_thread::get_id() << " Started waiting... \n" ; auto result = await calculate_the_answer(); cout << this_thread::get_id() << " : woke up, get " << result << endl ; } int main (int argc, char * argv[]) { coro().get(); cout << this_thread::get_id() << ": back in main\n" ; }
future<void>
和await
的語法實在是有點突兀(尤其是其他語言都用async
和await
之後) 如果我們拿掉await
會造成怎樣的結果
1 2 3 4 5 6 7 8 9 10 11 void noncoro () { cout << this_thread::get_id() << " Started waiting... \n" ; auto result = calculate_the_answer().get(); cout << this_thread::get_id() << " : woke up, get " << result << endl ; } int main (int argc, char * argv[]) { noncoro(); cout << this_thread::get_id() << ": back in main\n" ; }
可以看到兩個函數的不同
coro: Main Thread Invoke calculate_the_answer
-> Child Thread Return
noncoro: Main Thread Invoke calculate_the_answer
-> Main Thread Return
Complex Example 這個範例有點複雜,有時間在研究吧
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 #include <windows.h> #include <future> #include <iostream> #include <experimental/resumable> using namespace std ;using namespace std ::chrono;using namespace std ::experimental;auto operator await (system_clock::duration duration) { class awaiter { static void CALLBACK TimerCallback (PTP_CALLBACK_INSTANCE, void *Context, PTP_TIMER) { coroutine_handle<>::from_address(Context)(); } PTP_TIMER timer = nullptr ; system_clock::duration duration; public : explicit awaiter (system_clock::duration d) : duration (d) {} bool await_ready () const { return duration.count() <= 0 ; } bool await_suspend (coroutine_handle<> resume_cb) { int64_t relative_count = -duration.count(); timer = CreateThreadpoolTimer(TimerCallback, resume_cb.to_address(), nullptr ); SetThreadpoolTimer(timer, (PFILETIME)&relative_count, 0 , 0 ); return timer != 0 ; } void await_resume () {} ~awaiter() { if (timer) CloseThreadpoolTimer(timer); } }; return awaiter{ duration }; } future <void > test () { cout << this_thread::get_id() << ": sleeping...\n" ; await 1 s; cout << this_thread::get_id() << ": woke up\n" ; } int main () { test().get(); cout << this_thread::get_id() << ": back in main\n" ; }
Reference – Resumable functions in C++ – Coroutines in Visual Studio 2015 - Update 1 – Stackless coroutines with Visual Studio 2015