- 主题:觉得协程不是一个太好的编程模型
这个正是我想知道的,请详细介绍。
138楼我啰嗦了,就是要N个线程守候M个连接的方法。
已经提交的handle,送哪儿排队,如何守护?
【 在 z16166 的大作中提到: 】
: 收发全双工就是一种场景吧
: http是一收一发,其他的协议/场景是可能有收的同时也在发的,一个线程负责收,一个线程负责发。
: IOCP是n个线程处理m个连接,以WSASend()/WSARecv()请求的完成结果作为派发单位,派发给对应的线程(优先派发给正在运行的线程,减少线程切换开销),不管是哪个tcp连接的。当然,派发信息里携带的有是哪个tcp连接的context信息的(completion key。overlapped结构也可以扩展一下,存放自己的连接信息)。
: ...................
--
修改:ylh1969 FROM 221.218.60.*
FROM 221.218.60.*
我理解协程只是线程的语法糖而已
他规避了使用线程你要create和join的过程,把所有的await/async/yield的东西都放到
一个大的线程池里去调度,大部分时间不关心生产消费者模型condwait/notify这样的操
作。
【 在 finlab 的大作中提到: 】
: 协程很多场合是为了节省线程切换的成本,提高cpu的利用率。
: 但是经常把一个事情劈成两半,绕了半天还是要再捏到一起。
: 既然协程这么流行,那就不如在cpu和操作系统、编译器层面进行优化,
: ...................
--
FROM 119.139.198.*
排队和派发是windows内核实现的,并不开源,哈哈
让chatgpt帮你写个简单的IOCP例子就知道了
或者MS的这个例子
github dot com /microsoft/Windows-classic-samples/blob/main/Samples/Win7Samples/netds/winsock/iocp/server/IocpServer.Cpp
【 在 ylh1969 的大作中提到: 】
: 这个正是我想知道的,请详细介绍。
: 138楼我啰嗦了,就是要N个线程守候M个连接的方法。
: 已经提交的handle,送哪儿排队,如何守护?
--
FROM 222.131.200.*
iocp 可以达到你想要的效果。但是大家一般不会这么用。还是每个线程创建一个队列比较容易使用。
你的多线程协程是 golang, java 的玩法。以前还有个 bsd 系统也想干这个事情来着,忘了是哪个了,只记得后来失败掉。
c, c++, java 用这种 n:m 模型的协程是可以,但是过于粗暴。没有 golang 的 chan, 没有 CSP 和 Actor 模式,这种模型的协程思维负担很重。
【 在 ylh1969 的大作中提到: 】
: 不是这个意思。
: 是一个连接可以被任何一个线程处理,任何时候可以被任何线程丢进事件队列,并立即生效。队列可以被任意线程守候,但是一个fd只能激活一个线程,只能有一个线程持有。
: 许多线程守护许多socket。
: ...................
--
FROM 110.84.123.*
这种场景是 IO 非常大的时候用的?
线程1: 读数据, 处理数据, 读数据, 处理数据
线程2: 写数据, 准备数据, 写数据,准备数据
所以是怕“处理数据”时用时过长,影响准备数据写数据的过程是吧?
如果只用一个线程有一定的可能性写缓存为空时,线程还在处理数据,没时间准备数据。
但是,可以把处理数据与准备数据的过程放到另外一个线程去啊。岂不更妙?
线程1: 读数据 写数据 读数据
线程2: 处理数据 处理数据。
线程3: 准备数据 准备数据
线程中间通过线程间的通信一般很快可以忽略不计。
【 在 z16166 的大作中提到: 】
: 收发全双工就是一种场景吧
: http是一收一发,其他的协议/场景是可能有收的同时也在发的,一个线程负责收,一个线程负责发。
: IOCP是n个线程处理m个连接,以WSASend()/WSARecv()请求的完成结果作为派发单位,派发给对应的线程(优先派发给正在运行的线程,减少线程切换开销),不管是哪个tcp连接的。当然,派发信息里携带的有是哪个tcp连接的context信息的(completion key。overlapped结构也可以扩展
: ...................
--
修改:hgoldfish FROM 110.84.123.*
FROM 110.84.123.*
多谢。
【 在 z16166 的大作中提到: 】
: 排队和派发是windows内核实现的,并不开源,哈哈
: 让chatgpt帮你写个简单的IOCP例子就知道了
: 或者MS的这个例子
: ...................
--
FROM 221.218.60.*
全双工服务器远比你想象的复杂,典型的游戏服务器,有成千上万的客户端接入。
每一个accept的客户端,创建一个与socket关联的task,在系统中注册,一个新玩家。
随后这个task被丢进M:N的调度器,如epoll,准备接收它的信息。这个task不可以向自己的socket发送信息,因为别人也可以发,会打架。
如果需要发信息,把task+信息发送到一个队列,有一个线程守候这个队列,收到一个信息就把它发到对应的socket。
如果觉得吞吐量不够需要多加线程的话,需要考虑一个socket不能同时两个操作,搞点锁呀排队呀什么的。
在release task时,必须要考虑是否还在被使用。
所以我的问题是,什么东西可以搞M:N调度器,IOCP行吗?
据我所知,还有bsd的kqueue,线程条件锁。
【 在 hgoldfish 的大作中提到: 】
: 这种场景是 IO 非常大的时候用的?
: 线程1: 读数据, 处理数据, 读数据, 处理数据
: 线程2: 写数据, 准备数据, 写数据,准备数据
: ...................
--
修改:ylh1969 FROM 221.218.60.*
FROM 221.218.60.*
有成千上万个客户端接入的时候,才不应该使用 m:n 模型啊。此时一个 socket fd 的收发各使用一个线程,和一整个 socketfd 在一个线程内处理没啥区别。
m:n 模式最好的地方应该是那种超大带宽超大吞吐连接数量不多的场景才对。
【 在 ylh1969 的大作中提到: 】
: 全双工服务器远比你想象的复杂,典型的游戏服务器,有成千上万的客户端接入。
: 每一个accept的客户端,创建一个与socket关联的task,在系统中注册,一个新玩家。
: 随后这个task被丢进M:N的调度器,如epoll,准备接收它的信息。这个task不可以向自己的socket发送信息,因为别人也可以发,会打架。
: ...................
--
FROM 110.84.123.*
有成千上万个客户端接入的时候,才应该使用 m:n 模型。
n就是核数,当n全部忙起来的时候,就是系统最大能力发挥出来的时候。如果还有未决的任务,让它们排队等着,就是最好的,真要是建立成千上万的线程,大量时间花在调度上,会严重影响系统性能。
就像公共汽车,大家一拥而上,谁也上不去,排个队才好。
搞交易中间件的都知道,如果成千上万的客户端直接连数据库,很容易把数据库憋死。通过中间件,才能使系统运行顺畅,就是靠的中间件的M:N的功能。
如果系统能力不够,就增加核数,或增加服务器数量。
另外,调度器的性能,可以有一个指标反映:
最大响应时间:平均响应时间。
TUXEDO做到9,我的可以做到1.25。
【 在 hgoldfish 的大作中提到: 】
: 有成千上万个客户端接入的时候,才不应该使用 m:n 模型啊。此时一个 socket fd 的收发各使用一个线程,和一整个 socketfd 在一个线程内处理没啥区别。
: m:n 模式最好的地方应该是那种超大带宽超大吞吐连接数量不多的场景才对。
:
--
修改:ylh1969 FROM 221.218.60.*
FROM 221.218.60.*
所以说,协程的低成本切换没啥用。M:N的线程池模型已经完美解决CPU资源充分利用的问题,实现了0成本切换。
协程的意义在于,在M:N模型中,task陷入等待IO期间,能够释放线程,让它及时服务于等待处理的大批任务。
【 在 ylh1969 的大作中提到: 】
: 有成千上万个客户端接入的时候,才应该使用 m:n 模型。
: n就是核数,当n全部忙起来的时候,就是系统最大能力发挥出来的时候。如果还有未决的任务,让它们排队等着,就是最好的,真要是建立成千上万的线程,大量时间花在调度上,会严重影响系统性能。
: 就像公共汽车,大家一拥而上,谁也上不去,排个队才好。
: ...................
--
FROM 221.218.60.*