- 主题:觉得协程不是一个太好的编程模型
协程很多场合是为了节省线程切换的成本,提高cpu的利用率。
但是经常把一个事情劈成两半,绕了半天还是要再捏到一起。
既然协程这么流行,那就不如在cpu和操作系统、编译器层面进行优化,
降低线程上下文的切换开销,统一使用线程来完成cpu的分时复用。
--
FROM 223.72.70.*
协程机制与线程混用带来更高 的复杂性。
异步调用到最后,还是要同步,不如一开始就同步。
比如,await readAsyn(); await processAsyn() 这种模式不过是为了让出空闲时间的控制权。
不如就在底层实现同步的read,process, 上层就直接 顺序调用,
让操作系统或编译器层面解决线程空闲的调度。
【 在 poocp 的大作中提到: 】
: 你说了半天,这些问题还是多线程带来的啊。
:
--
FROM 223.72.70.*
放着那么多核不用,难道只在一个核上死磕吗?
【 在 VincentGe 的大作中提到: 】
: 这个复杂性在我看来更多是使用者带来的。
: 你难道要在一个协程中使用多线程模型吗?
:
: ...................
--
FROM 223.72.70.*
所以这里的问题还是现在单个线程占用的资源过多,线程是个比较“重”的调度单位
如果能低成本的创建并调度线程,那么你现在这种模式就非常简洁实用。
cpu硬件的趋势就是核心越来越多,充分利用多核比挖掘单核效率更重要。
如果为了充分利用单核,而给多线程模式带来障碍,那就得不偿失。
【 在 ylh1969 的大作中提到: 】
: 见10楼,最后一句。
: 而且,我就是在多线程模型中,有了协程需求。
: 整个系统是个线程池的socket服务器。
: ...................
--
FROM 223.72.70.*
我理想的模型是,设法降低单个线程的开销,然后创建大规模的线程池。
就不用担心线程阻塞不够用。系统会简单很多。
【 在 ylh1969 的大作中提到: 】
: 所以我是在线程池模式使用协程,线程不需要反复创建,线程池里就那么几个线程,一般是等于核数。它们的调度基于epoll,实现协程后,epoll就成了协程调度器。
: 系统启动后,所有的线程都在epoll_wait。直到出现一个被激活的fd,一个线程得到它的context,就是协程,然后转入这个协程,直到它需要再次IO,就会yield该线程,把自己排入epoll队列,线程跑去epoll_wait。这个线程下次可能得到另一个context,这个协程下次也可能被另一个线程捕获。
: 这种不绑定线程的协程体系,最省事,不需要写额外的调度和负载均衡策略。
--
FROM 223.72.70.*
现在协程流行的原因,还是线程的成本太高。
一个是现在的cpu每个核心有独立缓存,一个线程固定分配到一个核心是最好的,如果线程反复随机调度到不同核心,就会导致缓存的效率大幅下降,
另一个是操作系统层面,线程是一个比较重的对象,操作系统支持的线程数量上限也不高。
所以要用线程取代协程做并发,还是需要cpu结构和操作系统上的改进,能够高效支持大规模线程调度。
否则,就需要开发人员自己进行任务分割和调度,协程就存在流行的土壤。
【 在 mopo 的大作中提到: 】
: 好不好不知道,反正我编程10多年还真没怎么碰见过直接用协程的业务代码,就算是library也是凤毛麟角,也没出现过做架构和解决方案时非用不可的场景
: 对于并行和并发,实际情况是能把多线程玩好的已经不多了,单线程内做到伪并行也有很多路子,这个我一般交给专业的lib来做不会尝试自己造轮子
--
FROM 223.72.89.*
在线程池阻塞,是因为设计人员认为线程是一项紧缺的重型资源,所以给线程池分配较少的线程数。
按照我的想法,应该有更轻量级的更低开销的线程,这样开一个足够大的线程池,就基本不担心阻塞。
比如,原来只开10个线程,现在我开10000个线程。
当然,前提还是硬件和操作系统上要改进。
【 在 VincentGe 的大作中提到: 】
: 我有个疑惑,单线程我理解,但为什么多进程,多线程,线程池会阻塞?
: 是不是你等这个线程中的任务完成?
:
: ...................
--
FROM 223.72.68.*
协程调度同样有开销。
不过现在硬件线程切换核心的成本确实太高。 除了线程切换本身,切换后核心缓存作废影响也很大。
所以要硬件和操作系统一起想办法。
不过另一方面,对于IO密集的高并发,线程池里的线程多数时候在等待IO,并不会频繁发生调度。
【 在 ylh1969 的大作中提到: 】
: 线程数等于核数时效率最高,几乎没有调度开销。
: 当上千线程全忙时,调度开销相当可观。
--
FROM 223.72.68.*
现在服务器内存都上T了, 内存不是大问题。
大家在开发时,可以尽量对线程设置较小的栈空间。更好满足需要就好。
另外,有意识节省栈的使用,不要放大对象在栈上。
【 在 ylh1969 的大作中提到: 】
: 关键不是线程数,是栈数,无论线程协程,栈多了就有问题。每个栈2M的话,10000个线程,需要20G内存。当然也许将来不是问题。如果需要更多栈的话,问题更严重一些。
--
FROM 223.72.68.*
对,即使线程内部的跳转, 只要工作内容变化了,同样会导致缓存失效,这个跟线程切换是差不多的。
【 在 hgoldfish 的大作中提到: 】
: 协程调度的开销相对内核调度的开销低。但也算比较大的开销。因为有 cpu cache miss 还要保存恢复寄存器。
: 写大带宽 IO 程序最大的开销应该是陷入内核取数据,处理完成后,再次调用操作系统 API 把数据发送出去。收发数据都要陷入内核,即使是用上 mmap() 也是一样陷入内核。
: 现在 linux 的 io_uring 出来,有了这东东,可以做成不陷入内核了。这个才是王道。
: ...................
--
FROM 223.72.68.*