怎么理解IO多路复用(select)?
sockfd1,sockfd2,sockfd3..sockfdn 同时监听这n个客户,当其中有一个发来消息
时就从select的阻塞中返回,然后就调用read 读取收到消息的sockfd,然后又循环回select 阻塞;
这样就不会因为阻塞在其中一个上而不能处 理另一个客户的消息
我的问题是:
那这样子,在读取sockfd1的数据时,如果其它socket有数据来,那么也要等到sockfd1读取完了才能继续读取其它socket的数据吧。那这样子如果sockfd1的数据如果读取比较费时,那么其它socket不就被阻塞住了吗? 而且读取到的数据也要开启线程处理吧,那这和开启多个线程进行socket IO有什么区别呢?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
我觉得你的困惑在于为什么
select
就多路复用了?假设现在没有使用多路复用,你的服务器逻辑在多用户情况下会这样写:
1:主线程while循环
accept
,接收完连接之后创建新的线程并且将accept
返回的fd传入线程,此后这个线程while循环recv,也就是专门为一个客户端
服务,并且我们会把每个fd保存进一个全局结构。2:之后对于客户端发起的任何操作我们全部是在单独线程中处理的。
现在假设有10个客户端连接我们,他们同时活动时候,我们能处理是因为我们为每一个客户端配备了一个线程。但是缺点也很明显,操作系统能创建的线程数是一定的(32位,线程栈大小10M,默认创建300个左右),这也就限制了你系统的并发数。那用了
select
又是怎么的一种情况呢?1:我们给
select
的线程注册事件,假设注册500个事件。select
可以帮我们管理这些事件,主要我们注册了。之后我们处理这些事件可以选择不同的策略,可以开新的线程去处理,也可以直接用select
的线程处理,这当然是不耗时间的操作,其实一个线程就够了。2:这时候你要是还不太理解那我为什么要用它,是因为有些场景它是适用的,比如经常连接我的并发数非常大,假设10w,但是活动的就1000,那我不可能开10w线程什么也不干就等着吧,所以你用
select
(或者别的IO多路复用方法Epoll)处理就非常高效了。第一个确实会堵塞,但是读取会很快,都是在内存操作,基本上这里不会是瓶颈。
真正瓶颈一般就出现在你说的『读取到的数据也要开启线程处理』这块。数据处理如果需要大量计算或磁盘IO这种耗时较长的操作,确实是需要用开启线程处理。但也有不少情况是无需开启线程的,这就是纯事件驱动了,比如nginx作为简单的反向代理,只是把请求收进来再转出去,就无需多线程。
开启线程这块往往不是一个请求就建一个新线程,而是预先分配好线程池。
另外我们还可以把干活的线程池给移出去,放到别的进程或者机器上,这样当前的处理进程就没什么重活,也就无需多线程了,就像前面说的请求收进来简单处理就丢出去一样。
第一问,是被阻塞了。
“读取到的数据也要开启线程处理”,这句话没太看懂。