内核本身(将它Windows或Linux或更多的东西外来)负责做非阻塞I / O,并在NIO包的Java类(诸如信道,和选择器)仅是相当低的电平转换该API的内容。
低级内容要求您创建线程才能正确执行。基本NIO在Java中支持。*本身可以让你调用一个方法,该方法阻塞,直到至少1件事,你有兴趣发生任何数量的批量在一起无阻塞通道。例如,您可能有1000个代表网络套接字的开放通道都在等待“我是否对某些网络数据包到达这1000个开放套接字中的任何一个感兴趣”,然后调用方法说:“请休眠直到发生有趣的事情” 。如果您设置的应用程序调用此方法,然后处理所有有趣的东西,并返回到调用这个方法,你写一个相当低效的应用:的CPU往往已经远远超过一个核心,并且所有,但一个都睡着了即使什么也不做。正确的模型是让多个线程(每个内核或多或少)都运行相同的“用有趣的事情清单唤醒我”模型。除非故意使代码执行不当,否则您将无法摆脱线程。
所以,让我们假设说你将它设置正确:您有一个8核CPU,你有8个线程运行的“等待换有趣-东西,手柄插口,与活性数据”循环。
设想你的手柄插座码块的一部分。也就是说,它执行某些操作会导致CPU去检查其他作业,因为它必须等待网络或磁盘等。假设是因为您在其中放置了一些数据库查询,但您没有意识到数据库查询使用了(可能是本地,但仍然是)网络连接并击中了磁盘。这会是非常糟糕:你的CPU资源丰富地处理那些1000个传入的请求,但你的8个线程的整组都在等待的DB做的东西,而CPU可以对包进行分析和响应,它有没有任何事情要做,并且减少了等待数据库从磁盘获取记录所需的时间。
不好。因此,请NOT调用阻止代码。不幸的是,Java中有很多方法(包括Java核心库和第三方库)会阻塞。他们往往不被记录在案。对此没有真正的解决方案。
某些库确实提供了解决方案,但是如果提供了解决方案,则必须采用“回调”形式:以数据库查询为例:您需要做的就是获取该网络套接字,告诉它您正在,至少到目前为止,不再对传入数据感兴趣(您已经在等待数据库响应,试图为此套接字处理更多传入数据没有任何意义);相反,你要联想(和NIO API不支持此本身,你就必须建立某种框架)的DB连接本身为“我有兴趣,如果这个数据库查询有准备的响应”。 Java作为一种语言不适合采用这种方式编写,最终会出现“回调地狱”,这是javascript的工作方式。有回调地狱解决方案,但它仍然是复杂的,和java基本上不支持(例如,“产量”是一个东西,可以帮助。Java不支持收益率的概念)。
最后,有性能:为什么您要摆脱线程吗?
线程招致2个主要罚分:
上下文切换。当CPU必须跳到另一个线程时(因为它所在的线程需要等待磁盘或网络数据,因此现在无事可做),它需要跳到另一个代码位置并找出要加载的内存表进入缓存运行它。
堆栈。像几乎每个编程模型一样,都有一些称为“堆栈”的内存,其中包含局部变量以及调用您的方法的位置(以及调用它的方法,一直到主方法/线程运行)方法)。如果你得到一个堆栈跟踪,你看它的效果。在java中,每个线程都有1个栈,并且所有堆栈的大小相同。您可以使用-Xss JVM参数对其进行配置,最小值为1MB。意思是,如果您要同时使用4000个线程,则相当于4GB的堆栈,这是无法避免的(然后,您需要更多的内存用于堆等)。
但是,无阻塞没有太大的溶液,为任一这些问题:
当由于没有足够的数据来处理而移至另一个处理程序时,您还将进行上下文切换。这不是一个线程切换,但你仍然需要跳到内存完全不同的页面,并在现代建筑,访问内存中的一部分,是不是在高速缓存需要很长的时间。您只是用“线程上下文切换”代替了“内存页面缓存上下文切换”,却一无所获。
假设您是某种聊天应用程序,并且您已经从一个连接的客户端中收到一条要发送的消息。现在,您需要查询数据库,以查看该用户是否有权将此消息发布到它打算发送到的聊天通道,还需要查看是否还有其他需要更新的跟随模式设备。因为那是你想跳到另一份工作,而你等待阻塞操作。但是,你要记住这个国家的某个地方:发送用户的消息,你的数据库查询的结果。在线程模型,这个数据是自动地,隐式照顾你:这是在堆栈空间。如果您要使用完整的NIO,则需要自己进行管理,例如使用ByteBuffers。
是的,当您手动控制字节缓冲区时,可以将它们精确设置为所需的大小,并且通常远远小于1MB,因此您可以通过这种方式处理更多的同时连接。或者,您只需在服务器中扔掉64GB的RAM。
那么,务实的结果是这样:
NIO代码极难编写。使用诸如灰熊或Netty之类的抽象概念,因为它是火箭科学。
很少会更快。
如果需要跟踪的连接/文件/作业/等数据量很低,您可以同时进行更多操作。
这是一个有点像用汇编代替C,因为技术上可以挤出更多表现出来的手工做垃圾回收,而不是让Java的为您代劳。但还有一个原因,大多数人不使用汇编程序的东西,即使它在理论上是更快。有绝大多数的网络应用程序的被Java编写的,或Python或node.js中,或别的东西高电平的原因,而不是像C(++)或汇编非托管语言 立>