- 主题:觉得协程不是一个太好的编程模型
这在现代操作系统下都不是事。你看一下 mmap(MAP_STACK) 就是专门解决你这问题的。申请 1K 个线程,一共也就用 16MB.
【 在 ylh1969 的大作中提到: 】
: 关键不是线程数,是栈数,无论线程协程,栈多了就有问题。每个栈2M的话,10000个线程,需要20G内存。当然也许将来不是问题。如果需要更多栈的话,问题更严重一些。
--
FROM 59.61.196.*
现代操作系统也没那么弱鸡。1K 个线程就算全忙也就那样。
写这种类型的程序,尽量不要陷入内核才是王道。只要不陷入内核,操作系统每隔 10ms 切个时间片,一秒也就切 100 次。约等于零开销。
【 在 ylh1969 的大作中提到: 】
: 线程数等于核数时效率最高,几乎没有调度开销。
: 当上千线程全忙时,调度开销相当可观。
--
FROM 59.61.196.*
协程调度的开销相对内核调度的开销低。但也算比较大的开销。因为有 cpu cache miss 还要保存恢复寄存器。
写大带宽 IO 程序最大的开销应该是陷入内核取数据,处理完成后,再次调用操作系统 API 把数据发送出去。收发数据都要陷入内核,即使是用上 mmap() 也是一样陷入内核。
现在 linux 的 io_uring 出来,有了这东东,可以做成不陷入内核了。这个才是王道。
【 在 finlab 的大作中提到: 】
: 协程调度同样有开销。
: 不过现在硬件线程切换核心的成本确实太高。 除了线程切换本身,切换后核心缓存作废影响也很大。
: 所以要硬件和操作系统一起想办法。
: ...................
--
FROM 59.61.196.*
看我上面提到的 mmap(MAP_STACK),平时我都是给我的栈设置至少 8MB 的。如果递归调用多,设置成 1GB 都不是事。用到才会真正分配。
已经 64 位时代了大哥们!
以前你们用 32 位机受到内存空间只有 2GB 的限制用不上这好东东。现在可以普及了。
【 在 ylh1969 的大作中提到: 】
: 这个没法限制,有些应用递归多。
: 当你做一个框架时,没办法限制应用插件怎么个用法。
--
FROM 59.61.196.*
这个是 go, java 这些语言的做法。
我感觉你的实现是有 BUG 的。我记得你会迁移协程的内存,而不是使用我说的 mmap(MAP_STACK). 这样会导致引用到栈的指针出现问题。这是 c/c++ 在实现协程(纤程)时特有的问题。
go, java 不需要使用 mmap(MAP_STACK) 的原因是因为他们其实并不使用栈,底层实现是 stackless 是一种编译期的变换,而是使用的函数调用帧,这东东其实是存堆里的。
【 在 ylh1969 的大作中提到: 】
: 在一个应用模块里,使用了IO,就可能在IO后换线程。
: 如果没有IO,就可以一直运行下去,不受打扰,没有调度开销。
--
修改:hgoldfish FROM 27.152.128.*
FROM 27.152.128.*
应该没有了吧。
不过现在有些纤程的实现原理。比如国内的 libgo,这个现在已经停止维护了好像,以前 oppo 家开源的可惜了,它家就是基于复制内存的。这一招在其它语言里面没问题,但是在 c/cpp 里面有一定的概率导致崩溃。
【 在 z16166 的大作中提到: 】
: 啊,还有人在用32位的系统当服务器吗?哈哈
: 你这个是具体的应用,ylh1969搞的是一个能跑多个应用的平台,考虑的东西不同
--
FROM 59.61.196.*
是 mmap(MAP_STACK) 吗? 如果不是的话,mmap() 也会提前分配出内存,非常浪费内存。
【 在 ylh1969 的大作中提到: 】
: 我的协程栈是mmap分配的,向下生长。
: 线程池和协程栈尺寸一样,由配置文件决定。
: 函数调用桢就在栈里呀。
: ...................
--
FROM 59.61.196.*
有 MAP_GROWDOWN 就是对的。不会全部分配。
MAP_STACK 在 Linux 是 no-op,但是在 openbsd 里面是有效的。
想要跨多种平台的话,最好也加上。
上面两个 flag 经常一起出现。
【 在 ylh1969 的大作中提到: 】
: task->uc.uc_stack.ss_sp=mmap(0, use_stack_size,
: PROT_READ | PROT_WRITE | PROT_EXEC,
: MAP_PRIVATE | MAP_ANON | MAP_GROWSDOWN, -1, 0);
: ...................
--
修改:hgoldfish FROM 59.61.196.*
FROM 59.61.196.*
对。但是我的理解是这个用法多个线程一起服务同一个 socket 没有太大的意义吧?
你们是什么场景中,需要由多个线程来处理同一条 TCP 连接的?
【 在 z16166 的大作中提到: 】
: IOCP我用过,你问的两个,答案都是yes
--
FROM 110.81.0.*
iocp 可以达到你想要的效果。但是大家一般不会这么用。还是每个线程创建一个队列比较容易使用。
你的多线程协程是 golang, java 的玩法。以前还有个 bsd 系统也想干这个事情来着,忘了是哪个了,只记得后来失败掉。
c, c++, java 用这种 n:m 模型的协程是可以,但是过于粗暴。没有 golang 的 chan, 没有 CSP 和 Actor 模式,这种模型的协程思维负担很重。
【 在 ylh1969 的大作中提到: 】
: 不是这个意思。
: 是一个连接可以被任何一个线程处理,任何时候可以被任何线程丢进事件队列,并立即生效。队列可以被任意线程守候,但是一个fd只能激活一个线程,只能有一个线程持有。
: 许多线程守护许多socket。
: ...................
--
FROM 110.84.123.*