- 主题:用协程不如用go和rust
C++ 异步最大的开销,其实是在异步回调时,变量的生命周期经常会跳出函数的生命周期。。带来内存泄露和业务逻辑错误。是很多 C++ 程序崩溃的源头。
使用 C++ 协程之后,可以(接近)一整个程序里面看不到半个指针,连 shared_ptr<> 都不用,只要用好引用和 std::move() 就可以管理好内存。这个效果已经和 rust 很接近了,又不需要用复杂的类型系统。
【 在 munaiyi 的大作中提到: 】
: 是的,但是用c++协程不如用异步方式也许更好。
--
FROM 110.84.122.*
好吧,鱼老师
生成器是协程的特例
【 在 hgoldfish (老鱼) 的大作中提到: 】
: 不一定的啊。像刚才举的这个例子:
:
: for i in range(10):
: print(i)
--
FROM 221.216.140.*
我用c的协程都是没办法。
我做的是框架,应用是别人写的插件。人家应用可不管你什么同步异步。
在线程池服务器,人家就这么写了:
SendNet(bank,支付请求);
RecvNet(bank,回执);
银行何时回,不知道,人家就这么等着。不多的几个线程,堵死还不容易?
好大一个系统,就为这两句话,换rust?
所以就改RecvNet(),里边加上yield,让线程脱身干别的,等那边回话了,再resume回来接着干。
与上层应用插件没有关系。不需要他们管什么线程协程,同步异步这些p事。
就算是rust,怎么弄这两句话?别让应用逻辑考虑什么协程异步,全透明。
看了你们前边例子,想不出来怎么弄,才能让人家看不出来异步协程啥的。
【 在 munaiyi 的大作中提到: 】
: 是的,但是用c++协程不如用异步方式也许更好。
:
--
修改:ylh1969 FROM 221.218.60.*
FROM 221.218.60.*
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.*
谢,懂了。2,就是你之前说的用协程做词法分析。
1,就用13楼的流程。不过,我是用好多线程来干。
一个线程读,分组发给后边一堆线程,进行清洗入库。这样比协程更有效。
【 在 hgoldfish 的大作中提到: 】
: 我举个我最近用上 generator 的例子:
: 1. 有个模块从关系型数据库里面读取数据,清洗后写入到另外一个 OLAP 数据库。第一版的代码,先把数据清洗后,然后一次性入库到 OLAP 数据库。第二版改成 generator,一边清洗,一边入库。同时入库是按 16k 条纪录批量入库,有个缓冲。内存爆降到原来的 10% 不到。
: 2. 我写了一个表达式 DSL,lexer 和 parser 之间使用 generator 通信。所以 parser 是这样调用 lexer 的:
: ...................
--
修改:ylh1969 FROM 221.218.60.*
FROM 221.218.60.*
讲得不对啊。
C# 就是为了卖它家系统、数据库、它家office.
现在呢,linux化,为了卖它家的“云”。
【 在 hgoldfish 的大作中提到: 】
: 谁想用 c++ 呢。问题是很多领域,就只有 c++ 可用。
:
: 既然又要语言大战,我就扯淡一下。大多数语言 c/c++, java 以及一众脚本语言比如 python, perl, ruby, go 从来没有把自己定位成某个领域专用语言。所以有个好处是不会太限制程序员的上限。
:
: 反之,c#, js, lua 和 rust 在设计的时候都有明确的定位。rust 要搞系统编程。c# 和 js 是搞 GUI 的。这一类语言程序员少碰为妙。
--
FROM 124.160.153.*
cout是个IO,看不出这个协程与IO的并行关系。
协程准备数据,cout进行IO,它们还是串行的。
【 在 hgoldfish 的大作中提到: 】
: boost 的 context 以前也区分两种协程的。
: 事实上,c++20 的 coroutine 也支持 python 这种函数的,并不一定需要个调度器。比如:
: // 定义一个生成器函数
: ...................
--
修改:ylh1969 FROM 221.218.60.*
FROM 221.218.60.*
for(i:{1,2,3,4,5})
cout << i;
不是更省事,要协程干啥?
【 在 hgoldfish 的大作中提到: 】
: boost 的 context 以前也区分两种协程的。
: 事实上,c++20 的 coroutine 也支持 python 这种函数的,并不一定需要个调度器。比如:
: // 定义一个生成器函数
: ...................
--
修改:ylh1969 FROM 221.218.60.*
FROM 221.218.60.*
想不好co_await 与 epoll_wait,什么关系,怎么结合起来用。
【 在 hgoldfish 的大作中提到: 】
: boost 的 context 以前也区分两种协程的。
: 事实上,c++20 的 coroutine 也支持 python 这种函数的,并不一定需要个调度器。比如:
: // 定义一个生成器函数
: ...................
--
FROM 221.218.60.*