C++ 20 协程 之 Hello World(二)
C++ 20 协程 之 Hello World(二)
了解co_await的使用。
可等待对象awaitable
使用co_await关键字必须用于返回值为awaitable的对象的函数,如下图所示:
struct awaitable {
bool await_ready();
void await_suspend(coroutine_handle<>);
void await_resume();
};
调用如下:
co_await awaitable{};
等价于
if(!awaitable.await_ready()){
awaitable.await_suspend(); // 挂起协程
}
awaitable.await_resume(); // 恢复协程
awaitable对象的await_ready函数判断协程是否就绪,如果就绪的话直接恢复协程,继续向下执行;如果未就绪的话,需要执行await_suspend函数的逻辑,在实践中可能是一些耗时逻辑,如网络请求、IO操作、复杂CPU计算等,等待await_suspend函数的逻辑执行完成即可恢复协程让程序继续向下执行。
Hello World co_await的使用
下面是最简单的co_await的使用的Hello World版本。
struct HelloCoroutine {
public:
struct promise_type {
public:
promise_type(){
std::cout << "promise_type constructed\n";
}
~promise_type(){
std::cout << "promise_type destructed\n";
}
HelloCoroutine get_return_object(){
std::cout << "get_return_object\n";
return HelloCoroutine(std::coroutine_handle<promise_type>::from_promise(*this)); // 解引用
}
std::suspend_always initial_suspend(){
std::cout << "initial_suspend\n";
return {};
}
std::suspend_always final_suspend() noexcept {
std::cout << "final_suspend\n";
return {};
}
void return_void(){
std::cout << "return_void\n";
}
void unhandled_exception(){
std::cerr << "Coroutine encountered an exception.\n";
}
};
struct awaitable {
bool await_ready() const noexcept {
std::cout << "await_ready\n";
return false;
}
void await_suspend(std::coroutine_handle<promise_type> h) const noexcept {
std::cout << "await_suspend\n";
h.resume();
}
void await_resume() const noexcept {
std::cout << "await_resume\n";
}
};
HelloCoroutine(std::coroutine_handle<promise_type> coroutineHandle) : handle(coroutineHandle) {
std::cout << "HelloCoroutine constructed\n";
}
~HelloCoroutine() {
std::cout << "HelloCoroutine destructed\n";
handle.destroy();
}
void resume() { // 1
if (!handle.done()) {
handle.resume();
std::cout << "Coroutine resumed\n";
}
}
private:
std::coroutine_handle<promise_type> handle; // 指向协程帧
};
HelloCoroutine helloCoroutine(){
std::cout << "Hello, Coroutine before!" << std::endl;
co_await HelloCoroutine::awaitable{};
std::cout << "Hello, Coroutine after!" << std::endl;
}
void learn01(){
HelloCoroutine hello = helloCoroutine();
hello.resume();
}
没有什么好分析的HelloCoroutine对象的resume方法代表者开启协程,如果没有这个方法,则代表着这个协程被创建,但是协程没有被启动。
co_await返回值版本
实现如下功能:
一秒钟之后返回a+b的值。
struct HelloCoroutine {
public:
struct promise_type {
public:
promise_type(){
std::cout << "promise_type constructed\n";
}
~promise_type(){
std::cout << "promise_type destructed\n";
}
HelloCoroutine get_return_object(){
std::cout << "get_return_object\n";
return HelloCoroutine(std::coroutine_handle<promise_type>::from_promise(*this)); // 解引用
}
std::suspend_always initial_suspend(){
std::cout << "initial_suspend\n";
return {};
}
std::suspend_always final_suspend() noexcept {
std::cout << "final_suspend\n";
return {};
}
void return_void(){
std::cout << "return_void\n";
}
void unhandled_exception(){
std::cerr << "Coroutine encountered an exception.\n";
}
};
struct awaitable {
private:
int a, b, sum;
public:
awaitable(const int a, const int b) : a(a), b(b) {
std::cout << "awaitable constructed\n";
}
~awaitable(){
std::cout << "awaitable destructed\n";
}
bool await_ready() const noexcept {
std::cout << "await_ready\n";
return false;
}
void await_suspend(std::coroutine_handle<promise_type> h) noexcept {
std::cout << "await_suspend\n";
// 在后台线程中延迟后恢复协程
std::thread([this, h, delay = 1000]() -> void {
std::this_thread::sleep_for(std::chrono::milliseconds(delay)); // []()->void::delay delay 是闭包当中的一个属性
std::cout << "计算完成,恢复协程\n";
sum = a + b; // 模拟计算结果
h.resume(); // 自动恢复协程
}).join();
}
int await_resume() const noexcept {
std::cout << "await_resume\n";
return sum;
}
};
HelloCoroutine(std::coroutine_handle<promise_type> coroutineHandle) : handle(coroutineHandle) {
std::cout << "HelloCoroutine constructed\n";
}
~HelloCoroutine() {
std::cout << "HelloCoroutine destructed\n";
handle.destroy();
}
void resume() {
if (!handle.done()) {
handle.resume();
std::cout << "Coroutine resumed\n";
}
}
private:
std::coroutine_handle<promise_type> handle; // 指向协程帧
};
HelloCoroutine helloCoroutine(){
std::cout << "Hello, Coroutine before!" << std::endl;
auto result = co_await HelloCoroutine::awaitable(1, 2);
std::cout << "Hello, Coroutine after! a: " << result << std::endl;
}
void learn01(){
HelloCoroutine hello = helloCoroutine();
hello.resume(); // 开启协程
}
返回结果版本
struct HelloCoroutine {
public:
struct promise_type {
private:
int value = 0;
public:
promise_type(){
std::cout << "promise_type constructed\n";
}
~promise_type(){
std::cout << "promise_type destructed\n";
}
HelloCoroutine get_return_object(){
std::cout << "get_return_object\n";
return HelloCoroutine(std::coroutine_handle<promise_type>::from_promise(*this)); // 解引用
}
std::suspend_always initial_suspend(){
std::cout << "initial_suspend\n";
return {};
}
std::suspend_always final_suspend() noexcept {
std::cout << "final_suspend\n";
return {};
}
void return_value(int value){
std::cout << "return_void\n";
this->value = value;
}
void unhandled_exception(){
std::cerr << "Coroutine encountered an exception.\n";
}
int getValue() const { return value; }
};
struct awaitable {
private:
int a, b, sum;
public:
awaitable(const int a, const int b) : a(a), b(b) {
std::cout << "awaitable constructed\n";
}
~awaitable(){
std::cout << "awaitable destructed\n";
}
bool await_ready() const noexcept {
std::cout << "await_ready\n";
return false;
}
void await_suspend(std::coroutine_handle<promise_type> h) noexcept {
std::cout << "await_suspend\n";
// 在后台线程中延迟后恢复协程
std::thread([this, h, delay = 1000]() -> void {
std::this_thread::sleep_for(std::chrono::milliseconds(delay)); // []()->void::delay delay 是闭包当中的一个属性
std::cout << "计算完成,恢复协程\n";
sum = a + b; // 模拟计算结果
h.resume(); // 自动恢复协程
}).detach(); // 分离线程,使其在后台运行
}
int await_resume() noexcept {
std::cout << "await_resume\n";
return sum; // 获取计算结果
}
};
HelloCoroutine(std::coroutine_handle<promise_type> coroutineHandle) : handle(coroutineHandle) {
std::cout << "HelloCoroutine constructed\n";
}
~HelloCoroutine() {
std::cout << "HelloCoroutine destructed\n";
handle.destroy();
}
void resume() {
if (!handle.done()) {
handle.resume();
std::cout << "Coroutine resumed\n";
}
}
int getValue() const {
return handle.promise().getValue();
}
private:
std::coroutine_handle<promise_type> handle; // 指向协程帧
};
HelloCoroutine helloCoroutine(){
std::cout << "Hello, Coroutine before!" << std::endl;
auto result = co_await HelloCoroutine::awaitable(1, 2);
std::cout << "Hello, Coroutine after! a: " << result << std::endl;
co_return result;
}
void learn01(){
HelloCoroutine hello = helloCoroutine();
hello.resume(); // 开启协程
std::cout << "Coroutine returned value: " << hello.getValue() << std::endl;
}
查看如下代码,思考以下是异步还是同步?这样做是否有问题?
struct HelloCoroutine {
public:
struct promise_type {
public:
promise_type(){
std::cout << "promise_type constructed\n";
}
~promise_type(){
std::cout << "promise_type destructed\n";
}
HelloCoroutine get_return_object(){
std::cout << "get_return_object\n";
return HelloCoroutine(std::coroutine_handle<promise_type>::from_promise(*this)); // 解引用
}
std::suspend_always initial_suspend(){
std::cout << "initial_suspend\n";
return {};
}
std::suspend_always final_suspend() noexcept {
std::cout << "final_suspend\n";
return {};
}
void return_void(){
std::cout << "return_void\n";
}
void unhandled_exception(){
std::cerr << "Coroutine encountered an exception.\n";
}
};
struct awaitable {
private:
int a, b, sum;
public:
awaitable(const int a, const int b) : a(a), b(b) {
std::cout << "awaitable constructed\n";
}
~awaitable(){
std::cout << "awaitable destructed\n";
}
bool await_ready() const noexcept {
std::cout << "await_ready\n";
return false;
}
void await_suspend(std::coroutine_handle<promise_type> h) noexcept {
std::cout << "await_suspend\n";
// 在后台线程中延迟后恢复协程
std::thread([this, h, delay = 1000]() -> void {
std::cout << "Starting background computation in thread id: " << std::this_thread::get_id() << "\n";
std::this_thread::sleep_for(std::chrono::milliseconds(delay)); // []()->void::delay delay 是闭包当中的一个属性
std::cout << "计算完成,恢复协程\n";
sum = a + b;
h.resume(); // 自动恢复协程
}).join(); // 分离线程,使其在后台运行
}
int await_resume() noexcept {
std::cout << "await_resume\n";
std::cout << "await_resume Starting background computation in thread id: " << std::this_thread::get_id() << "\n";
return sum;
}
};
HelloCoroutine(std::coroutine_handle<promise_type> coroutineHandle) : handle(coroutineHandle) {
std::cout << "HelloCoroutine constructed\n";
}
~HelloCoroutine() {
std::cout << "HelloCoroutine destructed\n";
handle.destroy();
}
void resume() {
if (!handle.done()) {
handle.resume();
std::cout << "Coroutine resumed\n";
}
}
private:
std::coroutine_handle<promise_type> handle; // 指向协程帧
};
HelloCoroutine helloCoroutine(){
std::cout << "Hello, Coroutine before!" << std::endl;
int result = co_await HelloCoroutine::awaitable(1, 2);
std::cout << "Hello, Coroutine after result1: " << result << std::endl;
result = co_await HelloCoroutine::awaitable(1, 2);
std::cout << "Hello, Coroutine after result2: " << result << std::endl;
co_return;
}
void learn01(){
HelloCoroutine hello = helloCoroutine();
hello.resume(); // 开启协程
std::cout << "Coroutine returned value thread id: " << std::this_thread::get_id()<< std::endl;
}
并发计算
struct HelloCoroutine {
public:
struct promise_type {
public:
promise_type(){
std::cout << "promise_type constructed\n";
}
~promise_type(){
std::cout << "promise_type destructed\n";
}
HelloCoroutine get_return_object(){
std::cout << "get_return_object\n";
return HelloCoroutine(std::coroutine_handle<promise_type>::from_promise(*this)); // 解引用
}
std::suspend_always initial_suspend(){
std::cout << "initial_suspend\n";
return {};
}
std::suspend_always final_suspend() noexcept {
std::cout << "final_suspend\n";
return {};
}
void return_void(){
std::cout << "return_void\n";
}
void unhandled_exception(){
std::cerr << "Coroutine encountered an exception.\n";
}
};
struct awaitable {
private:
int a, b;
public:
std::promise<int> promise;
awaitable(const int a, const int b) : a(a), b(b) {
std::cout << "awaitable constructed\n";
}
~awaitable(){
std::cout << "awaitable destructed\n";
}
bool await_ready() const noexcept {
std::cout << "await_ready\n";
return false;
}
void await_suspend(std::coroutine_handle<promise_type> h) noexcept {
std::cout << "await_suspend\n";
// 在后台线程中延迟后恢复协程
std::thread([this, h, delay = 1000]() -> void {
std::cout << "Starting background computation in thread id: " << std::this_thread::get_id() << "\n";
std::this_thread::sleep_for(std::chrono::milliseconds(delay)); // []()->void::delay delay 是闭包当中的一个属性
std::cout << "计算完成,恢复协程\n";
promise.set_value(a + b);
h.resume(); // 自动恢复协程
}).detach(); // 分离线程,使其在后台运行
}
std::future<int> await_resume() noexcept {
std::cout << "await_resume\n";
std::cout << "await_resume Starting background computation in thread id: " << std::this_thread::get_id() << "\n";
return promise.get_future(); // 获取结果,阻塞等待
}
};
HelloCoroutine(std::coroutine_handle<promise_type> coroutineHandle) : handle(coroutineHandle) {
std::cout << "HelloCoroutine constructed\n";
}
~HelloCoroutine() {
std::cout << "HelloCoroutine destructed\n";
handle.destroy();
}
void resume() {
if (!handle.done()) {
handle.resume();
std::cout << "Coroutine resumed\n";
}
}
private:
std::coroutine_handle<promise_type> handle; // 指向协程帧
};
HelloCoroutine helloCoroutine(){
std::cout << "Hello, Coroutine before!" << std::endl;
auto result1 = co_await HelloCoroutine::awaitable(1, 2);
auto result2 = co_await HelloCoroutine::awaitable(3, 4);
std::cout << "Coroutine results: " << result1.get() << ", " << result2.get() << std::endl;
std::cout << "helloCoroutine returned value thread id: " << std::this_thread::get_id()<< std::endl;
co_return;
}
void learn01(){
HelloCoroutine hello = helloCoroutine();
hello.resume(); // 开启协程
std::cout << "Coroutine returned value thread id: " << std::this_thread::get_id()<< std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(3000));
}

C++ 20 协程 之 Hello World(二)
浙公网安备 33010602011771号