Open bennyhuo opened 2 years ago
首先谢谢作者。很好的一个系列, 发现代码的位置在前言有附录。大家可以去那儿下载。 https://github.com/bennyhuo/CppCoroutines.git
你看前言里面有写
首先谢谢作者。很好的一个系列, BTW:作者能把部分代码放入Github吗?现在有些代码是省略的。不太好看全。
— Reply to this email directly, view it on GitHub, or unsubscribe. You are receiving this because you authored the thread.Message ID: @.***>
好文! 是不是没必要单独维护一个is_ready 协程初始状态 suspend_never initial_suspend(){ return {}; } 下一个值 int next(){ int value=h.promise().value; h.resume(); return value; }
判断函数 bool has_next(){ if(h.done())return false; else return true; }
就可以解决的停止问题 关键还是promiseType的生命周期交到外部管理,这里的is_ready管理有点混乱,不好理解,而且可以删除
关键在于,调用hasnext的时候如果已经准备好值,是不能重复取下一个的,hasnext需要支持多次调用判断是否有下一个,但不能消费。你在next的时候直接 resume,那hasnext的功能就废了。而且resume完之后就可能没有值,也不能直接拿value返回。
其实没必要单独维护一个is_ready 协程初始状态 suspend_never initial_suspend(){ return {}; } 下一个值 int next(){ h.resume(); return h.promise().value; }
判断函数 bool has_next(){ if(h.done())return false; else return true; }
就可以解决的停止问题 关键还是promiseType的生命周期交到外部管理,这里的is_ready管理有点混乱,不好理解,而且可以删除
— Reply to this email directly, view it on GitHub, or unsubscribe. You are receiving this because you authored the thread.Message ID: @.***>
云编码果然不靠谱☺,刚才写了个demo,和你说的一样,需要个终止判断
好文马克
作者您好, 我想问一下就斐波那契数列这个例子而言. 使用协程的"显而易见的好处"具体指什么? 我本地使用Celero库测了一下两种方法的运行效率, 协程的效率远低于传统类成员函数调用的模式. 以下是我的例子和结果
// Fibonacci
Generator fibonacci() {
co_yield 0;
co_yield 1;
int a = 0, b = 1;
while (true) {
co_yield a + b;
b = a + b;
a = b - a;
}
}
void SequenceTest_Fibonacci(int times) {
auto gen = fibonacci();
for (int i = 0; i < times; ++i) {
gen.next();
}
}
// classical
class Fibonacci {
public:
int next() {
// 初值不符合整体的规律,需要单独处理
if (a == -1) {
a = 0;
b = 1;
return 0;
}
int next = b;
b = a + b;
a = b - a;
return next;
}
private:
int a = -1;
int b = 0;
};
void Classical_Fibonacci(int times) {
auto classical = Fibonacci();
for (int i = 0; i < times; ++i) {
classical.next();
}
}
BASELINE(Fibonacci, BaselineClassical, 10, 10000) { Classical_Fibonacci(100000); }
BENCHMARK(Fibonacci, CoroutineSequenceGenerator, 10, 10000) { SequenceTest_Fibonacci(100000); }
// result
Celero
Timer resolution: 0.001000 us
| Group | Experiment | Prob. Space | Samples | Iterations | Baseline | us/Iteration | Iterations/sec | RAM (bytes) |
|:--------------:|:---------------:|:---------------:|:---------------:|:---------------:|:---------------:|:---------------:|:---------------:|:---------------:|
|Fibonacci | BaselineClassic | Null | 10 | 10000 | 1.00000 | 374.37590 | 2671.11 | 8679424 |
|Fibonacci | CoroutineSequen | Null | 10 | 10000 | 7.85000 | 2938.84920 | 340.27 | 8679424 |
Completed in 00:06:05.465433
@L1nklink 作者您好, 我想问一下就斐波那契数列这个例子而言. 使用协程的"显而易见的好处"具体指什么? 我本地使用Celero库测了一下两种方法的运行效率, 协程的效率远低于传统类成员函数调用的模式. 以下是我的例子和结果
// Fibonacci Generator fibonacci() { co_yield 0; co_yield 1; int a = 0, b = 1; while (true) { co_yield a + b; b = a + b; a = b - a; } } void SequenceTest_Fibonacci(int times) { auto gen = fibonacci(); for (int i = 0; i < times; ++i) { gen.next(); } } // classical class Fibonacci { public: int next() { // 初值不符合整体的规律,需要单独处理 if (a == -1) { a = 0; b = 1; return 0; } int next = b; b = a + b; a = b - a; return next; } private: int a = -1; int b = 0; }; void Classical_Fibonacci(int times) { auto classical = Fibonacci(); for (int i = 0; i < times; ++i) { classical.next(); } } BASELINE(Fibonacci, BaselineClassical, 10, 10000) { Classical_Fibonacci(100000); } BENCHMARK(Fibonacci, CoroutineSequenceGenerator, 10, 10000) { SequenceTest_Fibonacci(100000); } // result Celero Timer resolution: 0.001000 us | Group | Experiment | Prob. Space | Samples | Iterations | Baseline | us/Iteration | Iterations/sec | RAM (bytes) | |:--------------:|:---------------:|:---------------:|:---------------:|:---------------:|:---------------:|:---------------:|:---------------:|:---------------:| |Fibonacci | BaselineClassic | Null | 10 | 10000 | 1.00000 | 374.37590 | 2671.11 | 8679424 | |Fibonacci | CoroutineSequen | Null | 10 | 10000 | 7.85000 | 2938.84920 | 340.27 | 8679424 | Completed in 00:06:05.465433
主要是可读性上的提升。如果考虑性能,得看使用场景,直接求值的话肯定是调用效率更高,因为协程为了支持“挂起”,会有一些开销。当然,这个也看编译器自身的优化了。
@bennyhuo
@L1nklink
主要是可读性上的提升。如果考虑性能,得看使用场景,直接求值的话肯定是调用效率更高,因为协程为了支持“挂起”,会有一些开销。当然,这个也看编译器自身的优化了。
感谢回复, 我的理解应该也是受使用场景的影响很大. 再次感谢这样的好文章.
@bennyhuo
@L1nklink
主要是可读性上的提升。如果考虑性能,得看使用场景,直接求值的话肯定是调用效率更高,因为协程为了支持“挂起”,会有一些开销。当然,这个也看编译器自身的优化了。
感谢回复, 我的理解应该也是受使用场景的影响很大. 再次感谢这样的好文章.
感谢支持~ 这一系列文章也可以在专栏中阅读哈,体验会更好一些:https://www.bennyhuo.com/book/cpp-coroutines/
我注意到有一点点笔误
explicit Generator(std::coroutine_handle<promise_type> handle) noexcept
: handle(handle) {}
感谢好文!
我注意到有一点点笔误
explicit Generator(std::coroutine_handle<promise_type> handle) noexcept : handle(handle) {}
感谢好文!
笔误具体是指?
我注意到有一点点笔误
explicit Generator(std::coroutine_handle<promise_type> handle) noexcept : handle(handle) {}
感谢好文!
笔误具体是指?
不好意思,我理解错了!我错误地以为 handle(handle)
有问题
https://www.bennyhuo.com/2022/03/11/cpp-coroutines-02-generator/
序列生成器是一个非常经典的协程应用场景。