但是我们避免了线程创建(这是昂贵的)。这是这种风格的核心优势吗?
如果我的线程池由2个执行者组成,并且两者都被阻塞等待某些内容,其他任务将不会被执行,对吧?如何避免这种情况?创建超过2个线程吗?
线程是相对昂贵的系统资源。例如,每个线程都需要为调用堆栈分配内存。这取决于操作系统,但通常是1或2 MB左右。这意味着启动数千个线程不是一个好主意——仅在1000个线程的调用堆栈上就会浪费1或2 GB的内存。
因此,为了更有效地处理事务,您希望限制线程的数量,例如使用线程池来处理工作。线程池使得管理正在使用的线程数成为可能。
然而,想象一下,您有一个有10个线程的线程池,然后有10个请求进来了。你的每个线程都将被保留来处理一个请求。当它们正在忙碌时,你无法处理第11个请求,因为没有空闲线程。如果你使用阻塞I/O,那么即使你的所有10个线程都没有做任何事情(等待I/O完成),请求#11也不能被处理...
当您使用非阻塞I/O时,线程永远不需要等待I/O——因此当处理请求#3被暂停因为需要I/O操作的结果时,正在处理它的线程可以暂时切换到处理其他请求。
因此,使用非阻塞I/O,您永远不会有等待的线程,并且更有效地使用系统资源。
这只有在从系统前端到后端都使用非阻塞I/O时才有效。如果在后端使用JDBC(一种阻塞API),那么你将失去非阻塞I/O的全部好处。
因此,如果您在后端拥有数据库,则最好使用支持非阻塞I/O的数据库。一些NoSQL数据库(如MongoDB)支持此功能,对于某些关系型数据库,有特殊的驱动程序/ API可用于支持此功能。在这种情况下,您将不会使用JDBC,因为JDBC是一个固有的阻塞API。Project Reactor是Reactive Streams规范的一种实现。规范概述可在ReactiveManifest找到。它不仅仅是创建一组线程并让它们完成工作,而是通过框架或运行时(在此示例中为Project Reactor)以这样的方式组织代码,使其表现为非阻塞状态。此外,整个系统实现必须按照这种方式进行,否则您将无法从响应式流中受益。
如果我的线程池包含2个执行器,并且两者都被阻止等待某些内容,则其他任务不会被执行,对吗?如何避免这种情况?创建超过2个线程?
答案可能是肯定的,也可能是否定的。框架可以或不可以创建线程。由于代码将在线程之间交错执行,因此在非阻塞系统中,包括低级操作(例如libuv I/O),不需要线程等待I/O操作的完成。同时,线程将执行一些有意义的事情。完成任务后将通知相关代码,可以由任何可用线程执行依赖代码。这种系统的目标是利用有限资源(线程)充分利用CPU。
选自http://www.reactive-streams.org。响应式流的主要目标是在异步边界上管理流数据的交换 - 想象将元素传递到另一个线程或线程池 - 同时确保接收方不被迫缓冲任意数量的数据。换句话说,在此模型中,反压力是其内在部分,以便允许在线程之间介导的队列受到限制。如果反压缩的通信是同步的(请参见响应式宣言),则异步处理的好处将被否定,因此必须注意强制所有Reactive Streams实现的完全非阻塞和异步行为。
React框架强制执行并帮助您从基础开始构建完全非阻塞的系统。