- 主题:用协程不如用go和rust
谁想用 c++ 呢。问题是很多领域,就只有 c++ 可用。
既然又要语言大战,我就扯淡一下。大多数语言 c/c++, java 以及一众脚本语言比如 python, perl, ruby, go 从来没有把自己定位成某个领域专用语言。所以有个好处是不会太限制程序员的上限。
反之,c#, js, lua 和 rust 在设计的时候都有明确的定位。rust 要搞系统编程。c# 和 js 是搞 GUI 的。这一类语言程序员少碰为妙。
【 在 munaiyi 的大作中提到: 】
: go 简单,快速上手
: rust 并发安全,该加锁的地方不加的话就编译不过去,睡觉也安稳。
--
FROM 110.84.122.*
不对。。协程 coroutine 应该是最基础的抽象。成为各种编程语言的基础概念。
Python 不就是这样么。
for i in range(10):
print(i)
这里的 range(10) generator 就是个协程。
【 在 ylh1969 的大作中提到: 】
: 没人为了协程而协程。
: 一定是在应用中遇到某种困难才想起协程。
: 这个应用可能是在某种生态环境中已经存在的了,想改,不那么容易吧?
: ...................
--
FROM 110.84.122.*
generator 有现实中的使用很广泛的啊。
【 在 ylh1969 的大作中提到: 】
: 看不出这种任务有何使用协程的必要。
: 是在print期间把资源让给其他协程吗?
--
FROM 110.84.122.*
不一定的啊。像刚才举的这个例子:
for i in range(10):
print(i)
就不包含事件循环调度。
【 在 hotfix 的大作中提到: 】
: 协程还包含调度吧
--
FROM 110.84.122.*
C++ 异步最大的开销,其实是在异步回调时,变量的生命周期经常会跳出函数的生命周期。。带来内存泄露和业务逻辑错误。是很多 C++ 程序崩溃的源头。
使用 C++ 协程之后,可以(接近)一整个程序里面看不到半个指针,连 shared_ptr<> 都不用,只要用好引用和 std::move() 就可以管理好内存。这个效果已经和 rust 很接近了,又不需要用复杂的类型系统。
【 在 munaiyi 的大作中提到: 】
: 是的,但是用c++协程不如用异步方式也许更好。
--
FROM 110.84.122.*
boost 的 context 以前也区分两种协程的。
事实上,c++20 的 coroutine 也支持 python 这种函数的,并不一定需要个调度器。比如:
// 定义一个生成器函数
std::generator<int> generate_numbers(int start, int end) {
for (int i = start; i <= end; ++i) {
co_yield i; // 使用 co_yield 生成值
}
}
int main() {
// 使用生成器
for (int num : generate_numbers(1, 5)) {
std::cout << num << " ";
}
std::cout << std::endl;
return 0;
}
以上代码 AI 生成。
【 在 hotfix 的大作中提到: 】
: 好吧,鱼老师
: 生成器是协程的特例
--
FROM 110.84.122.*
我举个我最近用上 generator 的例子:
1. 有个模块从关系型数据库里面读取数据,清洗后写入到另外一个 OLAP 数据库。第一版的代码,先把数据清洗后,然后一次性入库到 OLAP 数据库。第二版改成 generator,一边清洗,一边入库。同时入库是按 16k 条纪录批量入库,有个缓冲。内存爆降到原来的 10% 不到。
2. 我写了一个表达式 DSL,lexer 和 parser 之间使用 generator 通信。所以 parser 是这样调用 lexer 的:
token = next(lexer)
if token == "if":
condition_expr = parse_expr(lexer)
elif token == "let":
statement = parse_expr_statement(lexer)
elif ...
所以这里 lexer 和 parser 是两个协程,来回切换。
【 在 ylh1969 的大作中提到: 】
: 看不出这种任务有何使用协程的必要。
: 是在print期间把资源让给其他协程吗?
--
修改:hgoldfish FROM 110.84.122.*
FROM 110.84.122.*
这个列表经常是不确定的,比如数据来源于网络或者数据库。
【 在 ylh1969 的大作中提到: 】
: for(i:{1,2,3,4,5})
: cout << i;
: 不是更省事,要协程干啥?
: ...................
--
FROM 117.28.163.*
await, co_yield 都只涉及到纤程的切换。
epoll_wait() 是给事件循环纤程用的。这个纤程干的事情和操作系统内核差不多,专门搞调度。
但是纤程不一定要被某个控制中心调度。就像我前面说的,两个纤程可以自主地来回切换。完全不需要第三者的参与。这个时候,epoll_wait() 就没有用了。
事实上,我之前还考虑过完全没有事件循环,几个纤程自己内部任意协调的玩法。或者一次性从 epoll_wait() 返回多个事件,然后唤醒几个相关的纤程,让这几个纤程自己内部搞定完再返回事件循环的。不过不太好实现。API 不好弄。
【 在 ylh1969 的大作中提到: 】
: 明白,这只是例子。
: 不过还是不懂await如何与epoll_wait结合进行协程调度。
--
修改:hgoldfish FROM 117.28.163.*
FROM 117.28.163.*
协程本来就只是异步函数的一种写法而已啊。
性能是另外的事情。应该通过算法来提升。
另外我一直强调说协程是(纤程,线程,进程)三者的抽象。像 golang 的协程和 python 的协程实现就不太一样。
【 在 ylh1969 的大作中提到: 】
: 看了你的例子,就是一些语法变化,如parse,只不过把主程序和子程序掉了个个。对性能没有大的影响。
: 那个数据库洗数据的例子,协程也不如多线程处理的更好。
: 最需要协程的,就是同步IO异步化,这躲不掉事件处理。
: ...................
--
FROM 117.28.163.*