从业时间越久,发现互联网很多知识都是错的, 对小白误导有多深?

2022-04-18 22:04:26 +08:00
 jeesk
说说我自己的看法, 无论是 csdn 还是知乎, 在我最开始从业 java 的时候,觉得他们说得没有毛病? 从业几年后,发现很多都是在鬼扯。 就拿 BIO 和 NIO 谁性能好, 知乎上面竞争激烈,下面我粘贴一个知乎的回答。

回答 1:

首先要明确一点:nio 的适用于 io 高并发场景线程开销包括:内存开销(创建一个线程需要为其分配和维护一个 tcb 线程控制块保存上下文,一个线程私有的栈)、线程上下文切换的时间开销(保存上下文,加载下一个线程的上下文),在高并发环境下多出来的这一点点开销积累起来是非常可观的。若使用 bio ,高并发必然引起激烈 contention ,导致大量的上下文切换,若采用一个 io 一个线程模型,一个线程 M 级的空间消耗,内存消耗不起。而 netty 采用 nio 加 selector 加线程池基本上解决了上述问题:一是线程池限制了内存消耗,二是采用 selector 使得只有处于活动状态的 io 才会去占用线程,不会使线程白白因为 io 而阻塞,提高了线程利用率。

说说他们的谬论:
1. 使用 BIO 上下文切换厉害, 如果是相同 4 核 cpu , 无论我是用 bio 还是 nio ,都用 200 个线程, 这个时候对 cpu 的竞争到底有多剧烈? 我个人觉得差不了多少。 所以这个说法是错的。

2. 若采用一个 io 一个线程模型,一个线程 M 级的空间消耗。 这个就更扯淡了。 即使是 tomcat 在 8.5 以前也是 BIO 200 个线程, 都没有用到 1w 个线程? 为什么非要扯开大量线程呢? 并且 tomcat 在 8.5 以后才默认 nio.

3. 一是线程池限制了内存消耗,二是采用 selector 使得只有处于活动状态的 io 才会去占用线程. 那我 tomcat 用 BIO 没有内存限制? 没有内存限制岂不是早就宕机了? 再说说 selector 的问题, 我 NIO 在 readSelector 开 10 个线程去调用 select, 不都是阻塞的吗? 怎么会说在活动状态才占用线程?

然后你会发现这些错误的回答有很多,下面还有大量的小白点赞,觉得说得很对。 但是一经脑子思考就发现, 这绝对是坑 B.

如果有不同意见的小伙伴可以留言,我觉得这个可以作为一个面试题。
17803 次点击
所在节点    Java
154 条回复
liuhan907
2022-04-20 13:41:48 +08:00
@jeesk 浏览器的 js 一直都是单线程的,你总不能说 worker 算多线程吧(
nothingistrue
2022-04-20 14:01:32 +08:00
@lmshl 客户端应用读取一个文件准备编辑,说直白点就是记事本,这你也要用 NIO 去读取文件吗。虽然 Java 桌面应用很拉跨,但你也不能假定 Java 就只是搞 Web 服务器或者大型计算的,有些场景就是简简单单的线性同步处理,这时候你用 NIO 那就是杀鸡用牛刀。

@jeesk 同步异步这里我草率了,NIO 是确实是同步非阻塞的。NIO 跟 BIO 区别的是任务切换的效率,跟同步异步没多大关系,BIO 也能做异步。他俩用哪个,主要还得看并发。
nothingistrue
2022-04-20 14:03:40 +08:00
@liuhan907 @lmshl 异步跟单线程不冲突,用线程池处理异步是 Java 的专用方式,其他语言处理异步不是用的线程池。
liuhan907
2022-04-20 14:10:45 +08:00
@nothingistrue 异步和同步和你用什么处理没关系。准备读取数据的时候数据已经复制到用户缓冲就是异步,否则是同步。线程池那些都是后话。
defage
2022-04-20 14:19:31 +08:00
@jeesk 我这是杠。行吧。
32G 我笔记本都有 32G 呢。
lmshl
2022-04-20 15:07:20 +08:00
@nothingistrue 还真都用异步 /nio 去读区的,Android 有 kotlin flow ,compose-jb 给搬到桌面端来了,无非就是多个 suspend / await 的事。而且我 Electron 压根就不可能用同步方法去读文件好吧,直接把 UI 卡白屏了,谁不是写个异步 /nio 读取呢。

只要你习惯了这事,就跟呼吸一样自然,说白了还是写的少了。
nothingistrue
2022-04-20 15:11:06 +08:00
@lmshl 你把响应式处理 /流式处理,跟 NIO 搞混了吧。
Joker123456789
2022-04-20 16:28:35 +08:00
我觉得你需要补充一下 ,TCP, HTTP 协议的相关知识。 搞清楚,线程是在什么时候开的,什么时候结束的。

我用大白话说一下吧:

BIO 是打电话,如果同时很多人打进来 你就需要很多的手机 来处理。 并且每个电话接通后 你都必须完整的处理成功后才能挂断( BIO 就是必须处理完成才能挂断,千万别跟我杠 你可以先挂断 去接别的电话,因为这是不可以的), 你自己脑补一下,电话多了以后,接电话的人有多崩溃。

NIO 是发信息,如果同时很多人找你,你只是会收到很多信息而已,一部手机就可以处理了,而且你可以自己阅读信息的内容,来决定 先处理哪个,后处理哪个。

这么说,你应该有点概念了吧?

我再详细一点:

BIO, 电话接通后,那头跟你说:我这边有一份文件,我念给你听哦, 然后 你拿起纸笔,一边听,一边写, 在他念完之前 你都必须 一直听着,即使信号不好 导致断断续续的,即使他念了几句,跑去上厕所了,又或者 他故意 一段一段的念给你听,每段之间 都要去上一次厕所,或者吃一次零食。 你都必须 老老实实的 拿着电话在这等,不能处理别的, 也就是说你一直被占线了。

NIO ,那头 给你发的短信有多少,你就写多少,写完了就去看下条短信,完全不用卡在这等这个人,如果没有短信进来,你还可以休息一会。

这么说 是不是又更清楚了??

在网络通讯中,服务端需要接收到一个完整的报文,才能交给应用层去处理,也就是说,你必须要 等电话那头的人把一整段文件念给你听,并且你已经全部写在纸上了,才能交给应用层。

你在你的题目中描述的场景,他不属于 NIO ,也不属于 BIO ,他是个纯应用层的场景, 他是发生在 接电话,或者读短信的那个人,把电话那头的人要发的文件全部写完之后,才发生的事。 这个层面 其实用什么 IO 都是一样的,

但是你现在好像只有这一层的概念,对 IO 那一层完全没概念,所以出现错误的结论 也不是稀奇, 再继续加油吧,以后学深一点再来质疑。
Joker123456789
2022-04-20 16:49:13 +08:00
@nothingistrue NIO 是同步非阻塞, 而且 IO 最大的应用场景 是 做网络通讯,不是读写文件。
araaaa
2022-04-20 17:35:33 +08:00
当你有几万条连接需要同时调度的时候就知道非阻塞的用处了
documentzhangx66
2022-04-20 17:41:02 +08:00
建议先玩一下 Factorio 这款游戏,以可视化的方式展示这类问题。
aguesuka
2022-04-21 11:56:01 +08:00
楼主还是表达有问题, 你直接贴知乎答案

```
假如有 10000 个连接,4 核 CPU ,那么 bio 就需要一万个线程,而 nio 大概就需要 5 个线程(一个接收请求,四个处理请求)。如果这 10000 个连接同时请求,那么 bio 就有 10000 个线程抢四个 CPU ,几乎每个 CPU 平均执行 2500 次上下文切换,而 nio 四个处理线程,几乎每个线程都对应一个 CPU ,也就是几乎没有上下文切换。效率就体现出来了。

链接: https://www.zhihu.com/question/59356897/answer/164387902
```

当然是错误的

```
说下我的理解哈:
前提:BIO 面向流,NIO 面向缓冲区
10000 个连接,4 核 CPU ,如果是 BIO ,那么 Client ->OS 这个过程是阻塞的,当其中 4 个线程获取到 CPU 等待 OS 读取资源,那么剩余 9996 个线程就阻塞等待 T1,假设 1 个线程等待 OS 读取资源需要阻塞 1s(其他耗时先不考虑哈),那么剩下的线程就需 9996/4s ,这就可怕了。
而 NIO 呢,当其中 4 个线程获取到 CPU 资源去缓冲区读取资源,发现 OS 还没把资源放到缓冲区中,就释放 CPU 资源去干其他事,让其他线程来试试。这就节省了阻塞时间。当然了,如果线程发现缓冲区有准备好的数据的时候,效率和 BIO 还是一样的,其他线程还是要等这 4 个线程读取完数据的(同步)。

个人理解,有偏差了还请大佬帮忙指正下。
```

楼下的小白就给误导了
diagnostics
324 天前
OP 现在还有新的理解吗?

NIO 的提升应该是用单个 IO 线程处理更多线程,实际的业务处理里面 NIO 和 BIO 是没有区别的。例如 Kafka 一个 Selector 负责 Accept ,一个线程池 Selector 负责读写就是因为单个 Selector 处理 Accept 和读写有瓶颈,希望更多的线程留给业务线程

> nio 性能压榨 bio , 其实是错的。我自己用 4 核 8g 的服务器测试过。webflux 并不能缩短应用处理时间,只有让时间更加平稳,而普通 bio 的处理时间波动相当大。

这个是因为 BIO 会导致 Queuing networks ,你可以看看相关论文,一般会有 LayerQueueingNetworks 来建模分析和优化
jeesk
324 天前
@diagnostics

> nio 性能压榨 bio , 其实是错的。我自己用 4 核 8g 的服务器测试过。webflux 并不能缩短应用处理时间,只有让时间更加平稳,而普通 bio 的处理时间波动相当大。

这里的观点是什么? 你看懂了吗?

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://ex.noerr.eu.org/t/847761

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX